├── .gitignore
├── LICENSE.md
├── README.md
├── UIssueTracker.sln
├── UIssueTracker
├── App.config
├── App.xaml
├── App.xaml.cs
├── Classes
│ └── Constants.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── UIssueTracker.csproj
├── UserControls
│ ├── IssueCard.xaml
│ ├── IssueCard.xaml.cs
│ ├── IssueDetails.xaml
│ ├── IssueDetails.xaml.cs
│ ├── IssueHistoryCard.xaml
│ └── IssueHistoryCard.xaml.cs
├── packages.config
└── uit_icon.ico
└── _config.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Satheesh (ryanjon2040)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unreal Issue Tracker
2 |
3 | [](https://imgur.com/a/cnZP2)
4 |
5 | **Unreal Issue Tracker** is a desktop app developed by **Satheesh (ryanjon2040)** for Unreal Community. This app reads the rss feeds from [Unreal Engine Issues](https://issues.unrealengine.com/) website and has the following features.
6 |
7 | - Up-to-date information about latest bugs and fixes.
8 | - Subscribe to specific issues.
9 | - Keeps a history of viewed issues.
10 | - and more...
11 |
12 | # Features
13 |
14 | ### Main Interface
15 | Get up-to-date information from the Unreal Engine Issues website. Expand an issue to read the description and you can click the link to go to that issue page.
16 | [](https://imgur.com/a/cnZP2)
17 |
18 | ### Issue Details
19 | Clicking on the **SHOW DETAILS** button will show current status of that issue with steps to reproduce and a link to AnswerHub or UDN (if available). From here, you can select **MORE INFORMATION** to see which component it affects and for what Engine versions. You can also click **SUBSCRIBE** to follow this event.
20 | [](https://imgur.com/a/cnZP2)
21 |
22 | ### History
23 | Unreal Issue Tracker will keep a history of all the issues you have visited.
24 | [](https://imgur.com/a/cnZP2)
25 |
26 | I hope you like this small app :).
27 |
28 | # Open Source
29 |
30 | Unreal Issue Tracker uses the following open source libraries:
31 |
32 | * [MaterialDesignInXamlToolkit](https://github.com/ButchersBoy/MaterialDesignInXamlToolkit) - Google's Material Design in XAML & WPF, for C# & Visual Basic.
33 | * [Feed Reader](https://github.com/codehollow/FeedReader) - C# RSS and ATOM Feed reader library.
34 | * [Html Agility Pack](http://html-agility-pack.net/) - Html Agility Pack (HAP).
35 | * [Newtonsoft JSON](https://www.newtonsoft.com/json) - Popular high-performance JSON framework for .NET
36 |
37 | ### Download
38 |
39 | Check the [Releases](https://github.com/ryanjon2040/Unreal-Issue-Tracker/releases) page to download the binary version of Unreal Issue Tracker.
40 |
41 | License
42 | ----
43 |
44 | [https://github.com/ryanjon2040/Unreal-Issue-Tracker/blob/master/LICENSE.md](MIT)
45 |
46 |
47 | **Free Software, Hell Yeah!**
48 |
--------------------------------------------------------------------------------
/UIssueTracker.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2020
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UIssueTracker", "UIssueTracker\UIssueTracker.csproj", "{D48705BF-338B-4495-AC43-683DA1A687CB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Debug|x64.ActiveCfg = Debug|Any CPU
17 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Debug|x64.Build.0 = Debug|Any CPU
18 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Debug|x86.ActiveCfg = Debug|Any CPU
19 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Debug|x86.Build.0 = Debug|Any CPU
20 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Release|x64.ActiveCfg = Release|Any CPU
21 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Release|x64.Build.0 = Release|Any CPU
22 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Release|x86.ActiveCfg = Release|Any CPU
23 | {D48705BF-338B-4495-AC43-683DA1A687CB}.Release|x86.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {3730186B-DCA8-49A7-AEBC-AC7A655BA8ED}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/UIssueTracker/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/UIssueTracker/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/UIssueTracker/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace UIssueTracker
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/UIssueTracker/Classes/Constants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text.RegularExpressions;
4 | using System.Windows.Media;
5 | using Newtonsoft.Json;
6 | using UIssueTracker.UserControls;
7 | using System.Collections.Generic;
8 | using Newtonsoft.Json.Linq;
9 |
10 | namespace UIssueTracker.Classes
11 | {
12 | public class Constants
13 | {
14 | public static readonly string PRODUCT_NAME = "Unreal Issue Tracker";
15 | public static readonly string BUG_URL = @"https://issues.unrealengine.com/feed/bugs";
16 | public static readonly string FIX_URL = @"https://issues.unrealengine.com/feed/fixes";
17 |
18 | private static readonly string IssueTrackerFileExtension = ".uitf";
19 | private static readonly string IssueFilesDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\" + PRODUCT_NAME + @"\";
20 | private static readonly string IssueTrackerHistoryDirectory = IssueFilesDirectory + @"History\";
21 | private static readonly string IssueTrackerHistoryFile = IssueTrackerHistoryDirectory + "IssueHistory.uithf";
22 |
23 | public enum IssueResolution
24 | {
25 | Backlogged,
26 | ByDesign,
27 | CannotReproduce,
28 | Duplicate,
29 | Fixed,
30 | NonIssue,
31 | Unresolved,
32 | WontDo,
33 | WontFix,
34 | None
35 | }
36 |
37 | private static void CreateIssueFileLocation()
38 | {
39 | if (Directory.Exists(IssueFilesDirectory) == false)
40 | {
41 | Directory.CreateDirectory(IssueFilesDirectory);
42 | }
43 | }
44 |
45 | private static void CreateHistoryFile()
46 | {
47 | if (File.Exists(IssueTrackerHistoryFile) == false)
48 | {
49 | if (Directory.Exists(IssueTrackerHistoryDirectory) == false)
50 | {
51 | Directory.CreateDirectory(IssueTrackerHistoryDirectory);
52 | }
53 | JObject EmptyJson = new JObject();
54 | File.WriteAllText(IssueTrackerHistoryFile, EmptyJson.ToString(Formatting.Indented));
55 | }
56 | }
57 |
58 | public static bool IsSubscribedToIssue(string IssueNumber)
59 | {
60 | return File.Exists(IssueFilesDirectory + IssueNumber + IssueTrackerFileExtension);
61 | }
62 |
63 | public static bool SaveToHistory(IssueDetails issueDetails)
64 | {
65 | CreateHistoryFile();
66 | HistoryIssue historyIssue = JsonConvert.DeserializeObject(File.ReadAllText(IssueTrackerHistoryFile));
67 | if (historyIssue.IssueHistory.ContainsKey(GetIssueNumber(issueDetails.IssueURL)) == false)
68 | {
69 | historyIssue.IssueHistory.Add(GetIssueNumber(issueDetails.IssueURL), issueDetails.CurrentIssueTitle);
70 | string serializedJson = JsonConvert.SerializeObject(historyIssue, Formatting.Indented);
71 | File.WriteAllText(IssueTrackerHistoryFile, serializedJson);
72 | return true;
73 | }
74 | return false;
75 | }
76 |
77 | public static bool SubscribeToIssue(IssueDetails issueDetails)
78 | {
79 | CreateIssueFileLocation();
80 | string IssueNumber = GetIssueNumber(issueDetails.IssueURL);
81 | if (IsSubscribedToIssue(IssueNumber) == false)
82 | {
83 | SubscribeIssue subscribeIssue = new SubscribeIssue();
84 | subscribeIssue.SubscribedIssueResolution = issueDetails.CurrentIssueStatus;
85 | subscribeIssue.SubscribedIssueTitle = issueDetails.CurrentIssueTitle;
86 | subscribeIssue.SubscribedIssueID = IssueNumber;
87 | subscribeIssue.SubscribedIssueLink = issueDetails.IssueURL;
88 | subscribeIssue.SubscribedIssueDescription = issueDetails.CurrentIssueDescription;
89 | subscribeIssue.SubscribedIssueRepro = issueDetails.CurrentIssueRepro;
90 | subscribeIssue.SubscribedIssueMoreInfo = issueDetails.CurrentIssueAnswerHubLink;
91 | string SubscribeIssueJson = JsonConvert.SerializeObject(subscribeIssue, Formatting.Indented);
92 | File.WriteAllText(IssueFilesDirectory + IssueNumber + IssueTrackerFileExtension, SubscribeIssueJson);
93 | return true;
94 | }
95 | return false;
96 | }
97 |
98 | public static void UnSubscribeFromIssue(string IssueNumber)
99 | {
100 | string FileLocation = IssueFilesDirectory + IssueNumber + IssueTrackerFileExtension;
101 | File.Delete(FileLocation);
102 | }
103 |
104 | public static SubscribeIssue GetSubscribedIssue(string IssueFilePath)
105 | {
106 | return JsonConvert.DeserializeObject(File.ReadAllText(IssueFilePath));
107 | }
108 |
109 | public static string GetIssueNumber(string IssueLink)
110 | {
111 | return IssueLink.Replace(@"https://issues.unrealengine.com/issue/", "");
112 | }
113 |
114 | public static string GetIssueFilesDirectory()
115 | {
116 | return IssueFilesDirectory;
117 | }
118 |
119 | public static string GetIssuesHistoryFile()
120 | {
121 | return IssueTrackerHistoryFile;
122 | }
123 |
124 | public static SolidColorBrush ToSolidColorBrush(string hex_code)
125 | {
126 | return (SolidColorBrush)new BrushConverter().ConvertFromString(hex_code);
127 | }
128 |
129 | public static IssueResolution GetResolution(string ResolutionName)
130 | {
131 | IssueResolution issueResolution = IssueResolution.None;
132 | switch (ResolutionName.ToLower())
133 | {
134 | case "backlogged":
135 | issueResolution = IssueResolution.Backlogged;
136 | break;
137 | case "by design":
138 | issueResolution = IssueResolution.ByDesign;
139 | break;
140 | case "cannot reproduce":
141 | issueResolution = IssueResolution.CannotReproduce;
142 | break;
143 | case "duplicate":
144 | issueResolution = IssueResolution.Duplicate;
145 | break;
146 | case "fixed":
147 | issueResolution = IssueResolution.Fixed;
148 | break;
149 | case "non-issue":
150 | issueResolution = IssueResolution.NonIssue;
151 | break;
152 | case "unresolved":
153 | issueResolution = IssueResolution.Unresolved;
154 | break;
155 | case "won't do":
156 | issueResolution = IssueResolution.WontDo;
157 | break;
158 | case "won't fix":
159 | issueResolution = IssueResolution.WontFix;
160 | break;
161 | default:
162 | break;
163 |
164 | }
165 | return issueResolution;
166 | }
167 |
168 | public static SolidColorBrush GetResolutionColor(string ResolutionName)
169 | {
170 | return GetColorByIssueResolution(GetResolution(ResolutionName));
171 | }
172 |
173 | private static SolidColorBrush GetColorByIssueResolution(IssueResolution issueResolution)
174 | {
175 | string hex_code = "#FF304FFE";
176 | switch(issueResolution)
177 | {
178 | case IssueResolution.Backlogged:
179 | hex_code = "#FF7F261D";
180 | break;
181 | case IssueResolution.ByDesign:
182 | hex_code = "#FF27AE60";
183 | break;
184 | case IssueResolution.CannotReproduce:
185 | hex_code = "#FFF39C12";
186 | break;
187 | case IssueResolution.Duplicate:
188 | hex_code = "#FF95A5A6";
189 | break;
190 | case IssueResolution.Fixed:
191 | hex_code = "#FF2ECC71";
192 | break;
193 | case IssueResolution.NonIssue:
194 | hex_code = "#FFBBBBBB";
195 | break;
196 | case IssueResolution.Unresolved:
197 | hex_code = "#FFE74C3C";
198 | break;
199 | case IssueResolution.WontDo:
200 | hex_code = "#FF171717";
201 | break;
202 | case IssueResolution.WontFix:
203 | hex_code = "#FF34495E";
204 | break;
205 | default:
206 | break;
207 |
208 | }
209 | return (SolidColorBrush)new BrushConverter().ConvertFromString(hex_code);
210 | }
211 |
212 | public static string RemoveHtmlTags(string html)
213 | {
214 | string ReturnValue = html.Replace(@"amp;", string.Empty);
215 | Regex.Replace(ReturnValue, "<.+?>", string.Empty);
216 | return ReturnValue;
217 | }
218 | }
219 |
220 | public class SubscribeIssue
221 | {
222 | public string SubscribedIssueID { get; set; }
223 | public string SubscribedIssueTitle { get; set; }
224 | public string SubscribedIssueResolution { get; set; }
225 | public string SubscribedIssueLink { get; set; }
226 | public string SubscribedIssueDescription { get; set; }
227 | public string SubscribedIssueRepro { get; set; }
228 | public string SubscribedIssueMoreInfo { get; set; } // AnswerHub or UDN link.
229 | }
230 |
231 | public class HistoryIssue
232 | {
233 | public Dictionary IssueHistory = new Dictionary();
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/UIssueTracker/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
24 |
27 |
30 |
31 |
34 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
56 |
57 |
58 |
59 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | # ISSUES FIXED
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
158 |
159 |
160 |
161 |
162 |
163 | HOLD ON...ALMOST THERE
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/UIssueTracker/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using CodeHollow.FeedReader;
2 | using System.Windows;
3 | using UIssueTracker.Classes;
4 | using UIssueTracker.UserControls;
5 | using System.IO;
6 | using System.Threading.Tasks;
7 | using System.Windows.Threading;
8 | using System;
9 |
10 | namespace UIssueTracker
11 | {
12 | ///
13 | /// Interaction logic for MainWindow.xaml
14 | ///
15 | public partial class MainWindow : Window
16 | {
17 | public MainWindow()
18 | {
19 | InitializeComponent();
20 | HistoryCategory.Visibility = Visibility.Collapsed;
21 | MyTransitioner.SelectedIndex = 0;
22 | Title = Constants.PRODUCT_NAME;
23 |
24 | Dispatcher.BeginInvoke((Action)LoadSubscribedIssuesAsync);
25 | LoadBugsAsync();
26 | LoadFixesAsync();
27 | LoadHistoryCards();
28 | }
29 |
30 | public void LoadHistoryCards()
31 | {
32 | HistoryContainer.Children.Clear();
33 | HistoryCategory.Visibility = Visibility.Collapsed;
34 | if (File.Exists(Constants.GetIssuesHistoryFile()))
35 | {
36 | HistoryIssue historyIssue = Newtonsoft.Json.JsonConvert.DeserializeObject(File.ReadAllText(Constants.GetIssuesHistoryFile()));
37 | foreach (var s in historyIssue.IssueHistory)
38 | {
39 | IssueHistoryCard issueHistoryCard = new IssueHistoryCard(s.Key, s.Value, this);
40 | HistoryContainer.Children.Add(issueHistoryCard);
41 | HistoryCategory.Visibility = Visibility.Visible;
42 | }
43 | }
44 | }
45 |
46 | public async void LoadSubscribedIssuesAsync()
47 | {
48 | await Task.Factory.StartNew(() =>
49 | {
50 | Dispatcher.BeginInvoke(new Action(() =>
51 | {
52 | if (Directory.Exists(Constants.GetIssueFilesDirectory()))
53 | {
54 | string[] SubscribedIssues = Directory.GetFiles(Constants.GetIssueFilesDirectory());
55 | SubscribedIssuesContainer.Children.Clear();
56 | int FixedIssues = 0;
57 | int TotalIssuesSubscribed = 0;
58 | foreach (string s in SubscribedIssues)
59 | {
60 | TotalIssuesSubscribed++;
61 | SubscribeIssue subscribeIssue = Constants.GetSubscribedIssue(s);
62 | IssueCard issueCard = new IssueCard(subscribeIssue.SubscribedIssueTitle, subscribeIssue.SubscribedIssueDescription, subscribeIssue.SubscribedIssueLink, this, null, true);
63 | if (issueCard.HasIssueResolutionChanged(s, out Constants.IssueResolution OutChangedResolution) == false)
64 | {
65 | if (OutChangedResolution != Constants.IssueResolution.Fixed)
66 | {
67 | SubscribedIssuesContainer.Children.Add(issueCard);
68 | }
69 | else
70 | {
71 | FixedIssues++;
72 | }
73 | }
74 | }
75 | if (FixedIssues > 0)
76 | {
77 | NumberOfIssuesFixed.Text = string.Format("{0}/{1} ISSUE(S) HAS BEEN FIXED!", FixedIssues, TotalIssuesSubscribed);
78 | NumberOfIssuesFixedDialogHost.IsOpen = true;
79 | }
80 | }
81 | }));
82 | });
83 | }
84 |
85 | private async void LoadBugsAsync()
86 | {
87 | Feed feed = await FeedReader.ReadAsync(Constants.BUG_URL);
88 | foreach (var item in feed.Items)
89 | {
90 | BugsContainer.Children.Add(new IssueCard(item.Title, item.Description, item.Link, this, true));
91 | }
92 | BugsLoadingBar.Visibility = Visibility.Collapsed;
93 | }
94 |
95 | private async void LoadFixesAsync()
96 | {
97 | Feed feed = await FeedReader.ReadAsync(Constants.FIX_URL);
98 | foreach (var item in feed.Items)
99 | {
100 | FixesContainer.Children.Add(new IssueCard(item.Title, item.Description, item.Link, this, false));
101 | }
102 | FixesLoadingBar.Visibility = Visibility.Collapsed;
103 | }
104 |
105 | private void SearchIssue_Btn_Click(object sender, RoutedEventArgs e)
106 | {
107 | ShowTransitioner(@"https://issues.unrealengine.com/issue/" + IssueSearchText.Text, null, false);
108 | }
109 |
110 | public void ShowTransitioner(string Link, string Title, bool bIsSubscribedCard)
111 | {
112 | MyDialogHost.IsOpen = true;
113 | MyTransitioner.SelectedIndex = 1;
114 | IssueDetail.LoadIssue(Link, Title, bIsSubscribedCard, this);
115 | MyDialogHost.IsOpen = false;
116 | }
117 |
118 | private void UE4_Twitter_Click(object sender, RoutedEventArgs e)
119 | {
120 | System.Diagnostics.Process.Start(@"https://twitter.com/UnrealEngine");
121 | }
122 |
123 | private void UE4_FB_Click(object sender, RoutedEventArgs e)
124 | {
125 | System.Diagnostics.Process.Start(@"https://www.facebook.com/UnrealEngine/");
126 | }
127 |
128 | private void UE4_Git_Click(object sender, RoutedEventArgs e)
129 | {
130 | System.Diagnostics.Process.Start(@"https://github.com/EpicGames/UnrealEngine");
131 | }
132 |
133 | private void Satheesh_Twitter_Click(object sender, RoutedEventArgs e)
134 | {
135 | System.Diagnostics.Process.Start(@"https://twitter.com/ryanjon2040");
136 | }
137 |
138 | private void Satheesh_FB_Click(object sender, RoutedEventArgs e)
139 | {
140 | System.Diagnostics.Process.Start(@"https://www.facebook.com/satheeshpv");
141 | }
142 |
143 | private void Satheesh_Git_Click(object sender, RoutedEventArgs e)
144 | {
145 | System.Diagnostics.Process.Start(@"https://github.com/ryanjon2040");
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/UIssueTracker/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("Unreal Issue Tracker")]
11 | [assembly: AssemblyDescription("Desktop app designed to interact with Unreal Engine issues.")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("Satheesh (ryanjon2040)")]
14 | [assembly: AssemblyProduct("UIssueTracker")]
15 | [assembly: AssemblyCopyright("Copyright © 2018 - Satheesh (ryanjon2040)")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/UIssueTracker/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UIssueTracker.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UIssueTracker.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/UIssueTracker/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/UIssueTracker/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UIssueTracker.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/UIssueTracker/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/UIssueTracker/UIssueTracker.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D48705BF-338B-4495-AC43-683DA1A687CB}
8 | WinExe
9 | UIssueTracker
10 | UIssueTracker
11 | v4.6.1
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 |
17 |
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 | uit_icon.ico
40 |
41 |
42 |
43 | ..\packages\CodeHollow.FeedReader.1.1.0.2\lib\net452\CodeHollow.FeedReader.dll
44 |
45 |
46 | ..\packages\HtmlAgilityPack.1.6.13\lib\Net45\HtmlAgilityPack.dll
47 |
48 |
49 | ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll
50 |
51 |
52 | ..\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.dll
53 |
54 |
55 | ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 4.0
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | MSBuild:Compile
80 | Designer
81 |
82 |
83 |
84 | IssueCard.xaml
85 |
86 |
87 | IssueDetails.xaml
88 |
89 |
90 | IssueHistoryCard.xaml
91 |
92 |
93 | MSBuild:Compile
94 | Designer
95 |
96 |
97 | App.xaml
98 | Code
99 |
100 |
101 | MainWindow.xaml
102 | Code
103 |
104 |
105 | Designer
106 | MSBuild:Compile
107 |
108 |
109 | Designer
110 | MSBuild:Compile
111 |
112 |
113 | Designer
114 | MSBuild:Compile
115 |
116 |
117 |
118 |
119 | Code
120 |
121 |
122 | True
123 | True
124 | Resources.resx
125 |
126 |
127 | True
128 | Settings.settings
129 | True
130 |
131 |
132 | ResXFileCodeGenerator
133 | Resources.Designer.cs
134 |
135 |
136 |
137 | SettingsSingleFileGenerator
138 | Settings.Designer.cs
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueCard.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueCard.xaml.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using System.Linq;
3 | using System.Text.RegularExpressions;
4 | using System.Windows.Controls;
5 | using UIssueTracker.Classes;
6 |
7 | namespace UIssueTracker.UserControls
8 | {
9 | ///
10 | /// Interaction logic for IssueCard.xaml
11 | ///
12 | public partial class IssueCard : UserControl
13 | {
14 | private MainWindow mainWindow = null;
15 | private bool _bIsSubscribedCard = false;
16 | private string LoadURL = null;
17 |
18 | public IssueCard(string Title, string Description, string Link, MainWindow NewMainWindow, bool? bIsBug = null, bool bIsSubscribedCard = false)
19 | {
20 | InitializeComponent();
21 | mainWindow = NewMainWindow;
22 | CardTitle.Header = Title;
23 | CardDescription.Text = Constants.RemoveHtmlTags(Description);
24 | CardLink.Text = Link;
25 | LoadURL = Link;
26 | _bIsSubscribedCard = bIsSubscribedCard;
27 | if (bIsBug != null)
28 | {
29 | CardTitle.Foreground = (bool)bIsBug ? Constants.ToSolidColorBrush("#DDE21717") : Constants.ToSolidColorBrush("#DD4EE217");
30 | }
31 | }
32 |
33 | public bool HasIssueResolutionChanged(string FilePath, out Constants.IssueResolution ChangedResolution)
34 | {
35 | HtmlWeb web = new HtmlWeb();
36 | HtmlDocument htmlDoc = web.Load(LoadURL);
37 |
38 | string CurrentIssueStatus = htmlDoc.DocumentNode.SelectNodes("//*[@class='resolution']").Select(n => n.InnerText.Trim()).ElementAt(0);
39 | CardTitle.Foreground = Constants.GetResolutionColor(CurrentIssueStatus);
40 | if (Constants.GetSubscribedIssue(FilePath).SubscribedIssueResolution.ToLower() != CurrentIssueStatus.ToLower())
41 | {
42 | ChangedResolution = Constants.GetResolution(CurrentIssueStatus);
43 | return true;
44 | }
45 |
46 | ChangedResolution = Constants.IssueResolution.None;
47 | return false;
48 | }
49 |
50 | private void ShowDetails_Btn_Click(object sender, System.Windows.RoutedEventArgs e)
51 | {
52 | mainWindow.ShowTransitioner(CardLink.Text, CardTitle.Header.ToString(), _bIsSubscribedCard);
53 | }
54 |
55 | private void IssueLink_Click(object sender, System.Windows.RoutedEventArgs e)
56 | {
57 | System.Diagnostics.Process.Start(LoadURL);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueDetails.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 | DETAILS
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Unresolved
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueDetails.xaml.cs:
--------------------------------------------------------------------------------
1 | using HtmlAgilityPack;
2 | using System;
3 | using System.Linq;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using UIssueTracker.Classes;
7 |
8 | namespace UIssueTracker.UserControls
9 | {
10 | ///
11 | /// Interaction logic for IssueDetails.xaml
12 | ///
13 | public partial class IssueDetails : UserControl
14 | {
15 | public string IssueURL { get; private set; }
16 | public string CurrentIssueTitle { get; private set; }
17 | public string CurrentIssueStatus { get; private set; }
18 | public string CurrentIssueDescription { get; private set; }
19 | public string CurrentIssueRepro { get; private set; }
20 | public string CurrentIssueAnswerHubLink { get; private set; }
21 |
22 | private bool bDescriptionSet = false;
23 | private bool bStepsToReproduceSet = false;
24 | private string CurrentIssueNumber = null;
25 | private MainWindow OwningWindow = null;
26 |
27 | public IssueDetails()
28 | {
29 | InitializeComponent();
30 | }
31 |
32 | public void LoadIssue(string URL, string Title, bool bIsSubscribedCard, MainWindow mainWindow)
33 | {
34 | OwningWindow = mainWindow;
35 | CurrentIssueAnswerHubLink = null;
36 |
37 | bDescriptionSet = false;
38 | bStepsToReproduceSet = false;
39 | IssueURL = URL;
40 |
41 | HtmlWeb web = new HtmlWeb();
42 | HtmlDocument htmlDoc = web.Load(IssueURL);
43 |
44 | CurrentIssueNumber = Constants.GetIssueNumber(URL);
45 |
46 | if (Title == null)
47 | {
48 | Title = htmlDoc.DocumentNode.SelectNodes("//*[@class='visible-xs']").Select(n => n.InnerText.Trim()).ElementAt(0);
49 | }
50 | CurrentIssueTitle = Title;
51 | IssueTitle.Text = CurrentIssueTitle;
52 | CurrentIssueStatus = htmlDoc.DocumentNode.SelectNodes("//*[@class='resolution']").Select(n => n.InnerText.Trim()).ElementAt(0);
53 | IssueStatus.Text = CurrentIssueStatus;
54 |
55 | Subscribe_Btn.IsEnabled = true;
56 | if (bIsSubscribedCard == false)
57 | {
58 | Subscribe_Btn.IsEnabled = CurrentIssueStatus != "Fixed";
59 | }
60 | Subscribe_Btn.Content = Constants.IsSubscribedToIssue(CurrentIssueNumber) ? "UNSUBSCRIBE" : "SUBSCRIBE";
61 |
62 | IssueStatusColor.Background = Constants.GetResolutionColor(IssueStatus.Text);
63 |
64 | HtmlNode[] aNodes = htmlDoc.DocumentNode.SelectNodes("//a").ToArray();
65 | foreach (var n in aNodes)
66 | {
67 | string InnerText = n.InnerText.ToLower();
68 | if (n.Attributes["href"] != null
69 | && (InnerText == "answerhub" || InnerText == "udn")
70 | && CurrentIssueAnswerHubLink == null
71 | && (n.Attributes["href"].Value.EndsWith("ask.html") == false || n.Attributes["href"].Value.Contains("udn.unrealengine.com")))
72 | {
73 | CurrentIssueAnswerHubLink = n.Attributes["href"].Value;
74 | AnswerHubLinkBtn.Content = "VISIT ANSWER HUB";
75 | if (InnerText == "udn")
76 | {
77 | AnswerHubLinkBtn.Content = "VISIT UDN";
78 | }
79 | break;
80 | }
81 | }
82 | AnswerHubLinkBtn.IsEnabled = CurrentIssueAnswerHubLink != null;
83 |
84 | SideStackPanel.Children.Clear();
85 | HtmlNodeCollection thcells = htmlDoc.DocumentNode.SelectNodes("//table[@class='table']/tr/th");
86 | for (int i = 0; i < thcells.Count; ++i)
87 | {
88 | HtmlNodeCollection cells = htmlDoc.DocumentNode.SelectNodes("//table[@class='table']/tr/td");
89 | var DynamicPanelButton = new Button() { Content = Constants.RemoveHtmlTags(cells[i].InnerText) };
90 | DynamicPanelButton.IsEnabled = false;
91 | HtmlNode a = cells[i].SelectSingleNode("a[@href]");
92 | if (a != null)
93 | {
94 | DynamicPanelButton.Tag = Constants.RemoveHtmlTags(a.Attributes["href"].Value);
95 | DynamicPanelButton.Click += DynamicPanelButton_Click;
96 | DynamicPanelButton.IsEnabled = true;
97 | }
98 | SideStackPanel.Children.Add(DynamicPanelButton);
99 | }
100 |
101 | var texts = htmlDoc.DocumentNode.SelectNodes("//*[@class='panel-body']").Select(n => n.InnerText.Trim());
102 | foreach (var text in texts)
103 | {
104 | if (bDescriptionSet == false)
105 | {
106 | bDescriptionSet = true;
107 | CurrentIssueDescription = text;
108 | IssueDescription.Text = CurrentIssueDescription;
109 | continue;
110 | }
111 |
112 | if (bStepsToReproduceSet == false)
113 | {
114 | bStepsToReproduceSet = true;
115 | CurrentIssueRepro = text;
116 | IssueReproduceSteps.Text = CurrentIssueRepro;
117 | break;
118 | }
119 | }
120 |
121 | Constants.SaveToHistory(this);
122 | OwningWindow.LoadHistoryCards();
123 | }
124 |
125 | private void DynamicPanelButton_Click(object sender, RoutedEventArgs e) //Event which will be triggered on click of DynamicPanelButton
126 | {
127 | string Tag = ((Button)sender).Tag.ToString();
128 | Console.WriteLine("TAG: " + Tag);
129 | if (Tag.StartsWith(@"/issue/"))
130 | {
131 | System.Diagnostics.Process.Start(@"https://issues.unrealengine.com" + Tag);
132 | }
133 | else
134 | {
135 | System.Diagnostics.Process.Start(Tag);
136 | }
137 | }
138 |
139 | private void Subscribe_Btn_Click(object sender, RoutedEventArgs e)
140 | {
141 | if ((string)Subscribe_Btn.Content == "UNSUBSCRIBE")
142 | {
143 | Constants.UnSubscribeFromIssue(CurrentIssueNumber);
144 | Subscribe_Btn.Content = "SUBSCRIBE";
145 | }
146 | else
147 | {
148 | if (Constants.SubscribeToIssue(this))
149 | {
150 | Subscribe_Btn.Content = "UNSUBSCRIBE";
151 | }
152 | }
153 | OwningWindow.LoadSubscribedIssuesAsync();
154 | }
155 |
156 | private void AnswerHubLinkBtn_Click(object sender, RoutedEventArgs e)
157 | {
158 | System.Diagnostics.Process.Start(CurrentIssueAnswerHubLink);
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueHistoryCard.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 | ISSUE NUMBER
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/UIssueTracker/UserControls/IssueHistoryCard.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Windows.Controls;
3 | using UIssueTracker.Classes;
4 |
5 | namespace UIssueTracker.UserControls
6 | {
7 | ///
8 | /// Interaction logic for IssueHistoryCard.xaml
9 | ///
10 | public partial class IssueHistoryCard : UserControl
11 | {
12 | private string IssueKey = null;
13 | private MainWindow OwningWindow = null;
14 | public IssueHistoryCard(string NewIssueNumber, string NewIssueTitle, MainWindow mainWindow)
15 | {
16 | InitializeComponent();
17 | CardTitle.Text = string.Format("({0}) {1}", NewIssueNumber, NewIssueTitle);
18 | IssueKey = NewIssueNumber;
19 | OwningWindow = mainWindow;
20 | }
21 |
22 | private void RemoveFromHistory_Btn_Click(object sender, System.Windows.RoutedEventArgs e)
23 | {
24 | HistoryIssue historyIssue = Newtonsoft.Json.JsonConvert.DeserializeObject(File.ReadAllText(Constants.GetIssuesHistoryFile()));
25 | historyIssue.IssueHistory.Remove(IssueKey);
26 | string Result = Newtonsoft.Json.JsonConvert.SerializeObject(historyIssue, Newtonsoft.Json.Formatting.Indented);
27 | File.WriteAllText(Constants.GetIssuesHistoryFile(), Result);
28 | OwningWindow.LoadHistoryCards();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/UIssueTracker/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/UIssueTracker/uit_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanjon2040/Unreal-Issue-Tracker/ddc2dd16547985cfa6679afa5f826f253a8183e1/UIssueTracker/uit_icon.ico
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-tactile
--------------------------------------------------------------------------------