1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-05-10 17:34:07 +02:00

Finish refactoring context menu structures & fix bugs from previous commits

This commit is contained in:
chylex 2018-08-10 00:58:44 +02:00
parent a7d90dc708
commit 9088b8cd07
3 changed files with 145 additions and 85 deletions

View File

@ -32,8 +32,7 @@ abstract class ContextMenuBase : IContextMenuHandler{
private const CefMenuCommand MenuReadApplyROT13 = (CefMenuCommand)26509;
private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
protected ContextInfo.LinkInfo LastLink { get; private set; }
protected ContextInfo.ChirpInfo LastChirp { get; private set; }
protected ContextInfo.ContextData Context { get; private set; }
private readonly AnalyticsFile.IProvider analytics;
@ -41,23 +40,12 @@ protected ContextMenuBase(AnalyticsFile.IProvider analytics){
this.analytics = analytics;
}
private void ResetContextInfo(){
LastLink = default(ContextInfo.LinkInfo);
LastChirp = default(ContextInfo.ChirpInfo);
TweetDeckBridge.ContextInfo.Reset();
}
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
ResetContextInfo();
Context = TweetDeckBridge.ContextInfo.Reset();
}
else{
LastLink = TweetDeckBridge.ContextInfo.Link;
LastChirp = TweetDeckBridge.ContextInfo.Chirp;
if (LastLink.Type == ContextInfo.LinkType.Unknown){
LastLink = new ContextInfo.LinkInfo(parameters);
}
Context = TweetDeckBridge.ContextInfo.Create(parameters);
}
if (parameters.TypeFlags.HasFlag(ContextMenuType.Selection) && !parameters.TypeFlags.HasFlag(ContextMenuType.Editable)){
@ -70,11 +58,9 @@ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser bro
string TextOpen(string name) => "Open "+name+" in browser";
string TextCopy(string name) => "Copy "+name+" address";
string TextSave(string name) => "Save "+name+" as...";
ContextInfo.LinkType type = LastLink.Type;
if (type == ContextInfo.LinkType.Generic && !LastLink.UnsafeUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
if (TwitterUtils.RegexAccount.IsMatch(LastLink.UnsafeUrl)){
if (Context.Types.HasFlag(ContextInfo.ContextType.Link) && !Context.UnsafeLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
if (TwitterUtils.RegexAccount.IsMatch(Context.UnsafeLinkUrl)){
model.AddItem(MenuOpenLinkUrl, TextOpen("account"));
model.AddItem(MenuCopyLinkUrl, TextCopy("account"));
model.AddItem(MenuCopyUsername, "Copy account username");
@ -86,19 +72,20 @@ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser bro
model.AddSeparator();
}
else if (type == ContextInfo.LinkType.Video){
if (Context.Types.HasFlag(ContextInfo.ContextType.Video)){
model.AddItem(MenuOpenMediaUrl, TextOpen("video"));
model.AddItem(MenuCopyMediaUrl, TextCopy("video"));
model.AddItem(MenuSaveMedia, TextSave("video"));
model.AddSeparator();
}
else if (type == ContextInfo.LinkType.Image && LastLink.Url != TweetNotification.AppLogo.Url){
else if (Context.Types.HasFlag(ContextInfo.ContextType.Image) && Context.MediaUrl != TweetNotification.AppLogo.Url){
model.AddItem(MenuViewImage, "View image in photo viewer");
model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
model.AddItem(MenuSaveMedia, TextSave("image"));
if (LastChirp.Images.Length > 1){
if (Context.Chirp.Images.Length > 1){
model.AddItem(MenuSaveTweetImages, TextSave("all images"));
}
@ -111,15 +98,15 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
switch(commandId){
case MenuOpenLinkUrl:
OpenBrowser(control, LastLink.Url);
OpenBrowser(control, Context.LinkUrl);
break;
case MenuCopyLinkUrl:
SetClipboardText(control, LastLink.UnsafeUrl);
SetClipboardText(control, Context.UnsafeLinkUrl);
break;
case MenuCopyUsername: {
string url = LastLink.UnsafeUrl;
string url = Context.UnsafeLinkUrl;
Match match = TwitterUtils.RegexAccount.Match(url);
SetClipboardText(control, match.Success ? match.Groups[1].Value : url);
@ -128,11 +115,11 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
}
case MenuOpenMediaUrl:
OpenBrowser(control, TwitterUtils.GetMediaLink(LastLink.Url, ImageQuality));
OpenBrowser(control, TwitterUtils.GetMediaLink(Context.MediaUrl, ImageQuality));
break;
case MenuCopyMediaUrl:
SetClipboardText(control, TwitterUtils.GetMediaLink(LastLink.Url, ImageQuality));
SetClipboardText(control, TwitterUtils.GetMediaLink(Context.MediaUrl, ImageQuality));
break;
case MenuViewImage: {
@ -147,7 +134,7 @@ void ViewImage(string path){
}
}
string url = LastLink.Url;
string url = Context.MediaUrl;
string file = Path.Combine(BrowserCache.CacheFolder, TwitterUtils.GetImageFileName(url) ?? Path.GetRandomFileName());
control.InvokeAsyncSafe(() => {
@ -169,9 +156,9 @@ void ViewImage(string path){
}
case MenuSaveMedia: {
bool isVideo = LastLink.Type == ContextInfo.LinkType.Video;
string url = LastLink.Url;
string username = LastChirp.Authors.LastOrDefault();
bool isVideo = Context.Types.HasFlag(ContextInfo.ContextType.Video);
string url = Context.MediaUrl;
string username = Context.Chirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
if (isVideo){
@ -188,8 +175,8 @@ void ViewImage(string path){
}
case MenuSaveTweetImages: {
string[] urls = LastChirp.Images;
string username = LastChirp.Authors.LastOrDefault();
string[] urls = Context.Chirp.Images;
string username = Context.Chirp.Authors.LastOrDefault();
control.InvokeAsyncSafe(() => {
TwitterUtils.DownloadImages(urls, username, ImageQuality);
@ -220,7 +207,7 @@ void ViewImage(string path){
}
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
ResetContextInfo();
Context = TweetDeckBridge.ContextInfo.Reset();
}
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){

View File

@ -1,6 +1,7 @@
using CefSharp;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Management;
using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Handling{
@ -56,12 +57,12 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
InsertSelectionSearchItem(model, MenuSearchInColumn, "Search in a column");
}
if (!string.IsNullOrEmpty(LastChirp.TweetUrl) && !isSelecting && !isEditing){
if (Context.Types.HasFlag(ContextInfo.ContextType.Chirp) && !isSelecting && !isEditing){
model.AddItem(MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
model.AddItem(MenuScreenshotTweet, "Screenshot tweet to clipboard");
if (!string.IsNullOrEmpty(LastChirp.QuoteUrl)){
if (!string.IsNullOrEmpty(Context.Chirp.QuoteUrl)){
model.AddSeparator();
model.AddItem(MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
@ -119,11 +120,11 @@ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser b
return true;
case MenuOpenTweetUrl:
OpenBrowser(form, LastChirp.TweetUrl);
OpenBrowser(form, Context.Chirp.TweetUrl);
return true;
case MenuCopyTweetUrl:
SetClipboardText(form, LastChirp.TweetUrl);
SetClipboardText(form, Context.Chirp.TweetUrl);
return true;
case MenuScreenshotTweet:
@ -131,11 +132,11 @@ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser b
return true;
case MenuOpenQuotedTweetUrl:
OpenBrowser(form, LastChirp.QuoteUrl);
OpenBrowser(form, Context.Chirp.QuoteUrl);
return true;
case MenuCopyQuotedTweetUrl:
SetClipboardText(form, LastChirp.QuoteUrl);
SetClipboardText(form, Context.Chirp.QuoteUrl);
return true;
case MenuWriteApplyROT13:

View File

@ -1,70 +1,54 @@
using CefSharp;
using System;
using CefSharp;
using TweetDuck.Core.Utils;
namespace TweetDuck.Core.Management{
sealed class ContextInfo{
public LinkInfo Link { get; private set; }
public ChirpInfo Chirp { get; private set; }
private LinkInfo link;
private ChirpInfo? chirp;
public ContextInfo(){
Reset();
}
public void SetLink(string type, string url){
Link = string.IsNullOrEmpty(url) ? new LinkInfo() : new LinkInfo(type, url);
link = string.IsNullOrEmpty(url) ? null : new LinkInfo(type, url);
}
public void SetChirp(string tweetUrl, string quoteUrl, string chirpAuthors, string chirpImages){
Chirp = new ChirpInfo(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
chirp = string.IsNullOrEmpty(tweetUrl) ? (ChirpInfo?)null : new ChirpInfo(tweetUrl, quoteUrl, chirpAuthors, chirpImages);
}
public void Reset(){
Link = new LinkInfo();
Chirp = new ChirpInfo();
public ContextData Reset(){
link = null;
chirp = null;
return ContextData.Empty;
}
public ContextData Create(IContextMenuParams parameters){
ContextData.Builder builder = new ContextData.Builder();
builder.AddContext(parameters);
if (link != null){
builder.AddOverride(link.Type, link.Url);
}
if (chirp.HasValue){
builder.AddChirp(chirp.Value);
}
return builder.Build();
}
// Data structures
public enum LinkType{
Unknown, Generic, Image, Video
}
public struct LinkInfo{
public LinkType Type { get; }
private sealed class LinkInfo{
public string Type { get; }
public string Url { get; }
public string UnsafeUrl { get; }
public LinkInfo(string type, string url){
switch(type){
case "link": Type = LinkType.Generic; break;
case "image": Type = LinkType.Image; break;
case "video": Type = LinkType.Video; break;
default: Type = LinkType.Unknown; break;
}
Url = url;
UnsafeUrl = url;
}
public LinkInfo(IContextMenuParams parameters){
ContextMenuType type = parameters.TypeFlags;
if (type.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
Type = LinkType.Image;
Url = parameters.SourceUrl;
UnsafeUrl = parameters.SourceUrl;
}
else if (type.HasFlag(ContextMenuType.Link)){
Type = LinkType.Generic;
Url = parameters.LinkUrl;
UnsafeUrl = parameters.UnfilteredLinkUrl;
}
else{
Type = LinkType.Unknown;
Url = string.Empty;
UnsafeUrl = string.Empty;
}
this.Type = type;
this.Url = url;
}
}
@ -85,5 +69,93 @@ public ChirpInfo(string tweetUrl, string quoteUrl, string chirpAuthors, string c
this.chirpImages = chirpImages;
}
}
// Constructed context
[Flags]
public enum ContextType{
Unknown = 0,
Link = 0b0001,
Image = 0b0010,
Video = 0b0100,
Chirp = 0b1000
}
public sealed class ContextData{
public static readonly ContextData Empty = new Builder().Build();
public ContextType Types { get; }
public string LinkUrl { get; }
public string UnsafeLinkUrl { get; }
public string MediaUrl { get; }
public ChirpInfo Chirp { get; }
public ContextData(ContextType types, string linkUrl, string unsafeLinkUrl, string mediaUrl, ChirpInfo chirp){
Types = types;
LinkUrl = linkUrl;
UnsafeLinkUrl = unsafeLinkUrl;
MediaUrl = mediaUrl;
Chirp = chirp;
}
public sealed class Builder{
private ContextType types = ContextType.Unknown;
private string linkUrl = string.Empty;
private string unsafeLinkUrl = string.Empty;
private string mediaUrl = string.Empty;
private ChirpInfo chirp = default(ChirpInfo);
public void AddContext(IContextMenuParams parameters){
ContextMenuType flags = parameters.TypeFlags;
if (flags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
types |= ContextType.Image;
types &= ~ContextType.Video;
mediaUrl = parameters.SourceUrl;
}
if (flags.HasFlag(ContextMenuType.Link)){
types |= ContextType.Link;
linkUrl = parameters.LinkUrl;
unsafeLinkUrl = parameters.UnfilteredLinkUrl;
}
}
public void AddOverride(string type, string url){
switch(type){
case "link":
types |= ContextType.Link;
linkUrl = url;
unsafeLinkUrl = url;
break;
case "image":
types |= ContextType.Image;
types &= ~(ContextType.Video | ContextType.Link);
mediaUrl = url;
break;
case "video":
types |= ContextType.Video;
types &= ~(ContextType.Image | ContextType.Link);
mediaUrl = url;
break;
}
}
public void AddChirp(ChirpInfo chirp){
this.types |= ContextType.Chirp;
this.chirp = chirp;
}
public ContextData Build(){
return new ContextData(types, linkUrl, unsafeLinkUrl, mediaUrl, chirp);
}
}
}
}
}