Current Formatting For Embed Fields
Here is an embed I currently use for my semi-public Ark Servers.
First field is the Map name,
Second field is the direct connect IP Address,
Third field is if/where there is a community base on that map.
As you can see it works as intended but if there's to much info on a single line in the field the formatting is screwed up. Is there a way to fix this?
I'm using 3 separate stream builders to build the different fields and then adding them to the embed. If code is needed I can post a "dumbed down version" so it doesn't take up the whole page.
var linkHeading = "steam://connect/";
var sb = new StringBuilder();
var sb2 = new StringBuilder();
var sb3 = new StringBuilder();
var embed = new EmbedBuilder();
embed.WithColor(new Color(0, 255, 0));
embed.Title = "List of Server Ips";
JObject o1;
using (StreamReader file = File.OpenText("serverips.json"))
using (JsonTextReader reader = new JsonTextReader(file))
{
o1 = (JObject)JToken.ReadFrom(reader);
}
var ipsObject = JsonConvert.DeserializeObject<Rootobject>(o1.ToString());
sb.AppendLine("The Island: ");
sb2.AppendLine($"{linkHeading}{ipsObject.TheIsland.ip}:{ipsObject.TheIsland.port}/");
if(ipsObject.TheIsland.comm != "")
{
sb3.AppendLine($"Comm: {ipsObject.TheIsland.comm}");
} else { sb3.AppendLine($"No Comm Info Available"); };
sb.AppendLine("Aberration: ");
sb2.AppendLine($"{linkHeading}{ipsObject.Aberration.ip}:{ipsObject.Aberration.port}/");
if (ipsObject.Aberration.comm != "")
{
sb3.AppendLine($"Comm: {ipsObject.Aberration.comm}");
} else { sb3.AppendLine($"No Comm Info Available"); };
embed.WithDescription($"Cluster Ip and Comm Information");
embed.AddField(x =>
{
x.Name = "Map";
x.Value = sb.ToString();
x.IsInline = true;
});
embed.AddField(x =>
{
x.Name = "IP";
x.Value = sb2.ToString();
x.IsInline = true;
});
embed.AddField(x =>
{
x.Name = "Comm?";
x.Value = sb3.ToString();
x.IsInline = true;
});
await Context.User.SendMessageAsync(null, false, embed.Build());
await ReplyAsync("Server Ip List was sent directly to your inbox! :)");
You don't have that much control over how embed fields are displayed. The only thing you control in regards to fields are if they inline or not. The rendering is completely up to Discord and the end users screen size. For example, your current output on mobile will ignore the inline setting and list the fields one on top of the other instead of side by side.
Unless your fields consistently contain a small amount of text each you can't guarantee how the end use will see the output. If you need to guarantee some sort of consistent structured display across all devices, your best bet is to use an image.
Related
We're developing a bot that proactively messages people in a group chat.
Bot mentions are showing blank on Desktop/Web chat view. Interestingly, on mobile and in the notification bar on the left, the full text does show correctly.
This issue may apply to other chats, but I have not tested.
I'm using similar code to the following Microsoft guide by constructing the mention object:
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-and-group-conversations?tabs=dotnet#add-mentions-to-your-messages
Yes, I have tried using XMLConvert on the name as in the example, however, that does not make a difference, in fact, it puts the XML verbatim into the message sent by the bot.
I've also submitted a bug report here, as I suspect it's a bug in Teams itself (although, I could not find any other mentions of this or other similar example code):
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/43922577-bot-mentions-to-meetings-groups-are-blank-on-deskt
Relevant C# code:
...
using (ConnectorClient _client = new ConnectorClient(new Uri(groupChat.ServiceUrl), GetMicrosoftAppCredentials(), new HttpClient()))
{
var theMessage = Activity.CreateMessageActivity();
theMessage.Text = messageDto.Message;
// Process the message text for <at>mentions</at>
var textMentions = System.Text.RegularExpressions.Regex.Matches(theMessage.Text, "<at>(.*?)</at>");
var mentionObjects = new List<Entity>(); // For storing the mentions
foreach (var textMention in textMentions)
{
// The mentioned person should be between the tags
var theName = textMention.ToString().Split(new string[] { "<at>", "</at>" }, StringSplitOptions.RemoveEmptyEntries)[0];
if (!String.IsNullOrEmpty(theName))
{
// Find the teamsUser based on their name
var teamsUser = _botContext.Users.FirstOrDefault(u => u.Name.Equals(theName));
if (teamsUser != null)
{
var mention = new Mention
{
Mentioned = new ChannelAccount(teamsUser.TeamsUserId),
Text = textMention.ToString()
};
mentionObjects.Add(mention);
}
}
}
theMessage.Entities = mentionObjects;
try
{
var response = await _client.Conversations.SendToConversationAsync(groupChat.GroupChatId, (Activity)theMessage);
return Ok(response.Id);
}
catch (Exception e)
{}
}
...
Desktop Teams Chat:
Activity shows name OK:
Mobile app looks OK:
Images edited for privacy
Try passing "User Name" also in ChannelAccount() like below:
var mention = new Mention
{
Mentioned = new ChannelAccount(
turnContext.Activity.From.Id,
**turnContext.Activity.From.Name,**
role: null,
aadObjectId: null),
Text = textMention.ToString()
};
I tried above code and it's working for me.
I'm working on report rendering with FastReports - I'm doing this coming from a system to render with Crystal Reports. When using Crystal, I found that preloading a report and then binding parameters on request sped up crystal dramatically, since most of the time for a small layout like an invoice is in the setup. I'm now trying to achieve the same with FastReports.
It's unclear how much time setup takes however, so I'd also be interested in whether this is not a worthwhile endeavour.
My issue is that I have used a JSON API call, and used ConnectionStringExpression with a single parameter. In a nutshell, changing the parameter does not reload the data when I call Prepare.
Here's my code, with the second report load taken out, it renders the same report twice.
var report = new Report();
report.Load("C:\\dev\\ia\\products\\StratusCloud\\AppFiles\\Reports\\SalesQuoteItems.frx");
var urlTemplate = "http://localhost:9502/data/sales-quote/{CardCode#}/{DocEntry#}";
var reportParms = new Dictionary<string, dynamic>();
reportParms.Add("CardCode#", "C20000");
reportParms.Add("DocEntry#", 77);
var connectionstring = "Json=" + System.Text.RegularExpressions.Regex.Replace(urlTemplate, "{([^}]+)}", (m) => {
if (reportParms.ContainsKey(m.Groups[1].Value))
{
return string.Format("{0}", reportParms[m.Groups[1].Value]);
}
return m.Value;
});
var dataapiparm = report.Dictionary.Parameters.FindByName("DataAPIUrl#");
if (dataapiparm != null)
{
dataapiparm.Value = connectionstring;
}
foreach(FastReport.Data.Parameter P in report.Dictionary.Parameters)
{
if (reportParms.ContainsKey(P.Name))
{
P.Value = reportParms[P.Name];
}
}
report.Prepare();
var pdfExport = new PDFSimpleExport();
pdfExport.Export(report, "test1.pdf");
//report = new Report();
//report.Load("C:\\dev\\ia\\products\\StratusCloud\\AppFiles\\Reports\\SalesQuoteItems.frx");
reportParms["DocEntry#"] = 117;
connectionstring = "Json=" + System.Text.RegularExpressions.Regex.Replace(urlTemplate, "{([^}]+)}", (m) => {
if (reportParms.ContainsKey(m.Groups[1].Value))
{
return string.Format("{0}", reportParms[m.Groups[1].Value]);
}
return m.Value;
});
dataapiparm = report.Dictionary.Parameters.FindByName("DataAPIUrl#");
if (dataapiparm != null)
{
dataapiparm.Value = connectionstring;
}
foreach (FastReport.Data.Parameter P in report.Dictionary.Parameters)
{
if (reportParms.ContainsKey(P.Name))
{
P.Value = reportParms[P.Name];
}
}
report.Prepare();
pdfExport.Export(report, "test2.pdf");
Cheers,
Mark
Fast Project definitely doesn't recalculate the ConnectionStringExpression on report.Prepare, so I went back to another method that I was looking at. It turns out that if the ConnectionString itself is rewritten, then report.Prepare does refetch the data.
A simple connection string without a schema takes a long time to process, so I remove everything beyond the semi-colon and keep it, replace the url portion of the connectionstring, and then stick teh same schema information back on the end.
Copying the schema information into each report generation connection string seems to remove around 10 seconds from report.Prepare!
At the moment it's the best that I can do, and I wonder if there is another more efficient method of rerunning the same report against new data (having the same schema).
I am trying to exclude Linkedin but when i checked UIActivityType Class, I found only below members.
AddToReadingList
AirDrop
AssignToContact
CopyToPasteboard
Mail
Message
OpenInIBooks
PostToFacebook
PostToFlickr
PostToTencentWeibo
PostToTwitter
PostToVimeo
Print
SaveToCameraRoll
Is there a way we can exclude linkedin?
Update:
I thought this radar concerning third-party values was closed, but it is still open :-(
http://openradar.appspot.com/20170408
...
The ExcludedActivityTypes is just an array of NSStrings that include the bundle id of the share extension. So use com.linkedin.LinkedIn.ShareExtension to exclude linkedin.
Example:
var activityItemsNSUrl = NSUrl.FromString("http://stackoverflow.com");
var activityItemsString = new NSString("StackOverflow");
var activityItems = new NSObject[] { activityItemsString, activityItemsNSUrl };
var activityViewController = new UIActivityViewController(activityItems, null)
{
ExcludedActivityTypes = new NSString[] {
UIActivityType.PostToVimeo,
new NSString("com.linkedin.LinkedIn.ShareExtension"),
UIActivityType.PostToFlickr
}
};
PresentViewController(activityViewController, true, () => { });
Re: https://developer.linkedin.com/docs/ios-sdk
When setting up a merge, the TortoiseSvn client has a wonderful checkbox labeled "Hide non-mergable revisions". I'm looking to reproduce the list of revisions that shows up when it's enabled using SharpSvn.
The TortoiseSvn documentation explains this checkbox:
When merge tracking is used, the log dialog will show previously merged revisions, and revisions pre-dating the common ancestor point, i.e. before the branch was copied, as greyed out. The Hide non-mergeable revisions checkbox allows you to filter out these revisions completely so you see only the revisions which can be merged.
How can I reproduce this functionality in SharpSvn code? I need a list of SvnLogEventArgs (or similar) that are candidates for merging.
Current status: I've only gotten as far as pulling the logs for both branches. I can't figure out how to get the appropriate svn:mergeinfo attribute or what to do with it once I get it.
I kept plugging away, and following links, and here's what I ended up with:
using (var client = new SvnClient())
{
var release = SvnTarget.FromUri(new Uri(#"https://******/branches/Release"));
var trunk = SvnTarget.FromUri(new Uri(#"https://******/trunk"));
string trunkMergeinfo, releaseMergeinfo;
client.GetProperty(release, "svn:mergeinfo", out releaseMergeinfo);
client.GetProperty(trunk, "svn:mergeinfo", out trunkMergeinfo);
var relInfos = releaseMergeinfo.Split("\n");
var trunkInfos = trunkMergeinfo.Split("\n");
// This is here because I don't know what will happen once I merge something into trunk.
Debug.Assert(relInfos.Except(trunkInfos).Count() == 1,"Too many unknown merge paths");
var trunklist = relInfos.SingleOrDefault(i => i.StartsWith("/trunk:"));
var revisions = trunklist.Replace("/trunk:", "").Split(",").SelectMany(t =>
{
// If the log contains a range, break it out to it's specific revisions.
if (t.Contains("-"))
{
var match = Regex.Match(t, #"(\d+)-(\d+)");
var start = int.Parse(match.Groups[1].Value);
var end = int.Parse(match.Groups[2].Value);
return Enumerable.Range(start, end - start + 1).ToArray();
}
else
return new[] { int.Parse(t) };
}).Select(x => (long)x);
Collection<SvnLogEventArgs> baseRevs;
// Why can't this take "trunk" or a property thereof as an argument?
client.GetLog(new Uri(#"https://******/trunk"), new SvnLogArgs { Start = 1725, End = SvnRevisionType.Head }, out baseRevs);
baseRevs.Reverse().Where(r => !revisions.Contains(r.Revision) ).Select(x => x.LogMessage).Dump();
}
Hopefully, this helps someone else, although I'll note that it does not have a lot of the sanity checking that I'd put in production code - this is the quick-and-dirty version.
Try SvnClient.ListMergesEligible:
http://sharpsvn.qqn.nl/current/html/M_SharpSvn_SvnClient_ListMergesEligible_1.htm
Edit.
SharpSVN seems bugged for me, so I went for cmd.
Check this out:
private static void mergelhetőVerziókListája()
{
string revíziók = cmd("svn", "mergeinfo --show-revs eligible \".../branches/dev\" \".../trunk\"");
}
private static string cmd(string utasítás, string paraméter)
{
StringBuilder eredmény = new StringBuilder();
Process cmd = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = utasítás,
Arguments = paraméter,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
cmd.Start();
while (!cmd.StandardOutput.EndOfStream)
{
string kimenet = cmd.StandardOutput.ReadLine();
eredmény.AppendLine(kimenet); //...
}
return eredmény.ToString();
}
Here is my code I am trying to get body of the email from textdata property but it is giving error object reference not set to instance of an object I dont have a clue what to do
IMAPConfig config = new IMAPConfig("imap-mail.outlook.com","name#hotmail.com", "password", true, true, "");
config.CacheFile = "";
IMAPClient client = null;
client = new IMAPClient(config, null, 5);
IMAPFolder f = client.Folders["Inbox"];
// Console.WriteLine(f.GetMessageByID(7049)) ;
int[] msgCount = null;
while (msgCount == null || msgCount.Length == 0)
{
msgCount = f.CheckForNewMessages();
Thread.Sleep(1000);
}
foreach (int id in msgCount)
{
IMAPMessage msg = f.GetMessageByID(id);
string a = null;
a = msg.TextData.TextData;
//MessageBox.Show(msg.TextData.ToString());
msg.MarkAsRead();
}
Seeing as how InterIMAP is a dead project, I would highly recommend switching to MailKit which is not only actively maintained (by me), but also has a lot more features (I mean, InterIMAP's home page says it will get support for copying messages soon and hasn't been updated since 2009), has a lot more users, and a lot fewer bugs. It's also a lot easier to use.
For example, here's how you would do what you are trying to do with MailKit:
using (var client = new ImapClient ()) {
client.Connect ("imap-mail.outlook.com", 993, true);
client.Authenticate ("name#hotmail.com", "password");
client.Inbox.Open (FolderAccess.ReadWrite);
for (int i = 0; i < client.Inbox.Count; i++) {
var message = client.Inbox.GetMessage (i);
var html = message.HtmlBody;
var text = message.TextBody;
// mark the message as read
client.Inbox.AddFlags (id, MessageFlags.Seen, true);
}
client.Disconnect (true);
}
I've also got MSDN-style documentation (that I'm always working on improving) at http://www.mimekit.net/docs that you might find helpful. If you have any questions, my email address can be found on the github project page (the "MailKit" link at the top of my answer).
It looks like you are using InterIMAP for this. If you look at the source code for IMAPMessage.TextData (https://interimap.codeplex.com/SourceControl/latest#InterIMAP/InterIMAP/Objects/IMAPMessage.cs) you can see that it will return null if there is no plain text body part in the message.
/// <summary>
/// The content of the message as plain text (if available)
/// </summary>
[XmlIgnore]
public IMAPMessageContent TextData
{
get
{
//RefreshData(true, false);
foreach (IMAPMessageContent content in _bodyParts)
{
if (content.ContentType.ToLower().Contains("plain"))
return content;
}
return null;
}
//set { _textData = value; }
}