/// <summary> /// Applies handling for subtitles to textview /// </summary> /// <param name="action">Action that should be started when the user interacts with the source.</param> /// <param name="sources">The parsed sources</param> /// <param name="textView">Textiew the SubtitleLinks should be attached to</param> /// <param name="text">Text representing the whole subtitle</param> public static void ApplySubtitlesLinks(this UITextView textView, IInteractiveSourceAction action, List <Source> sources, NSAttributedString text) { if (action == null) { return; } Dictionary <Source, FinalSourcePosition> sourcePositions = new Dictionary <Source, FinalSourcePosition>(); var formattedTextWithSubstitutes = new NSMutableAttributedString(text); // get the textpositions of each source and mark them foreach (var source in sources) { if (source == null) { continue; } int startIndex = text.Value.IndexOf(source.SubstituteText, StringComparison.Ordinal); var finalPostion = new FinalSourcePosition { Start = startIndex, End = startIndex + source.SubstituteText.Length - 1 }; sourcePositions.Add(source, finalPostion); var resources = IoCManager.Resolve <ApplicationResourcesProvider>(); formattedTextWithSubstitutes.AddAttribute(UIStringAttributeKey.ForegroundColor, (resources.TryGetResourceColorvalue("SecondaryColor")).ToUIColor(), new NSRange(finalPostion.Start, source.SubstituteText.Length)); } textView.AttributedText = formattedTextWithSubstitutes; // make the source links clickable textView.AddGestureRecognizer(new UITapGestureRecognizer(x => HandleTap(x, textView, sourcePositions, action))); }
/// <summary> /// Returns a SpannableString containing interactive sources for subtitles. /// </summary> /// <param name="action">Action that should be started when the user interacts with the source.</param> /// <param name="textWithSubstitutes">The parsed text with substitutes</param> /// <param name="sources">The parsed sources</param> /// <returns>A SpannableString parsed from the textWithSubstitutes for the subtitles. Returns null, if the provided action is null.</returns> public SpannableString CreateSubtitlesText(IInteractiveSourceAction action, string textWithSubstitutes, List <Source> sources) { if (action == null) { return(null); } var str = new SpannableString(textWithSubstitutes); foreach (var src in sources) { if (src == null) { continue; } str.SetSpan( ConvertSrcToClickableSpan(src, action), src.StartIndex, src.StartIndex + src.SubstituteText.Length, SpanTypes.ExclusiveExclusive); } return(str); }
/// <summary> /// Converts a source to a ClickableSpan that executes the specified action. /// </summary> /// <param name="src">Source that should be converted to a ClickableSpan.</param> /// <param name="action">Action that should be executed when the Click-event of the span is triggered.</param> /// <returns>ClickableSpan for the provided Source instance.</returns> private static ClickableSpan ConvertSrcToClickableSpan(Source src, IInteractiveSourceAction action) { if (src == null) { return(null); } InteractiveSourceClickableSpan span = new InteractiveSourceClickableSpan(); span.Click += v => action.Display(src); return(span); }
/// <summary> /// Returns a SpannableString containing interactive sources for subtitles. /// </summary> /// <param name="action">Action that should be started when the user interacts with the source.</param> /// <param name="textWithSubstitutes">The parsed text with substitutes</param> /// <param name="sources">The parsed sources</param> /// <returns>A SpannableString parsed from the textWithSubstitutes for the subtitles. Returns null, if the provided action is null.</returns> public SpannableString CreateSubtitlesText(IInteractiveSourceAction action, ISpanned textWithSubstitutes, List <Source> sources) { if (action == null) { return(null); } var sourcePositions = new Dictionary <Source, FinalSourcePosition>(); // get the textpositions of each source and mark them foreach (var source in sources) { if (source == null) { continue; } int startIndex = textWithSubstitutes.ToString().IndexOf(source.SubstituteText, StringComparison.Ordinal); sourcePositions.Add(source, new FinalSourcePosition { Start = startIndex, End = startIndex + source.SubstituteText.Length }); } var str = new SpannableString(textWithSubstitutes); foreach (var src in sourcePositions) { if (src.Key == null) { continue; } str.SetSpan( ConvertSrcToClickableSpan(src.Key, action), src.Value.Start, src.Value.End, SpanTypes.ExclusiveExclusive); } return(str); }
private static void HandleTap(UITapGestureRecognizer gestureRecognizer, UITextView textView, Dictionary <Source, FinalSourcePosition> sourcePositions, IInteractiveSourceAction action) { var point = gestureRecognizer.LocationInView(textView); point.Y += textView.ContentOffset.Y; var tapPos = textView.GetClosestPositionToPoint(point); // if a source link has been tapped: show the reference nint clickedPos = textView.GetOffsetFromPosition(textView.BeginningOfDocument, tapPos); int pos = Convert.ToInt32(clickedPos); var clickedSource = sourcePositions.SingleOrDefault(x => x.Value.Start <= pos && pos <= x.Value.End).Key; if (clickedSource != null) { action.Display(clickedSource); } }
protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); this.SetBinding(ActionProperty, "Action", BindingMode.TwoWay); Action = new SwitchTabAndScrollToSourceAction(this); }