Skip to content
This repository was archived by the owner on Jul 2, 2022. It is now read-only.

Commit 03fa771

Browse files
committed
You can now upload images in Markdown Composer
1 parent e1754e2 commit 03fa771

9 files changed

Lines changed: 251 additions & 26 deletions

File tree

CodeHub.Core/CodeHub.Core.iOS.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
<Compile Include="ViewModels\Gists\GistCreateViewModel.cs" />
131131
<Compile Include="Messages\GistAddMessage.cs" />
132132
<Compile Include="ViewModels\Repositories\RepositoriesTrendingViewModel.cs" />
133+
<Compile Include="Utils\MarkdownHtmlGenerator.cs" />
133134
</ItemGroup>
134135
<ItemGroup />
135136
<ItemGroup>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Text;
3+
4+
namespace CodeHub.Core.Utils
5+
{
6+
public static class MarkdownHtmlGenerator
7+
{
8+
public static string CreateFile(string content)
9+
{
10+
var markup = System.IO.File.ReadAllText("Markdown/markdown.html", Encoding.UTF8);
11+
12+
var tmp = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName() + ".html");
13+
using (var tmpStream = new System.IO.FileStream(tmp, System.IO.FileMode.Create))
14+
{
15+
var fs = new System.IO.StreamWriter(tmpStream, Encoding.UTF8);
16+
var dataIndex = markup.IndexOf("{{DATA}}", StringComparison.Ordinal);
17+
fs.Write(markup.Substring(0, dataIndex));
18+
fs.Write(content);
19+
fs.Write(markup.Substring(dataIndex + 8));
20+
fs.Flush();
21+
}
22+
return tmp;
23+
}
24+
}
25+
}
26+

CodeHub.Core/ViewModels/Repositories/ReadmeViewModel.cs

100755100644
Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using CodeFramework.Core.ViewModels;
77
using CodeFramework.Core.Services;
88
using CodeHub.Core.Services;
9+
using CodeHub.Core.Utils;
910

1011
namespace CodeHub.Core.ViewModels.Repositories
1112
{
@@ -66,27 +67,9 @@ protected override Task Load(bool forceCacheInvalidation)
6667
{
6768
_contentModel = x.Data;
6869
var data = _markdownService.Convert(Encoding.UTF8.GetString(Convert.FromBase64String(x.Data.Content)));
69-
Path = CreateHtmlFile(data);
70+
Path = MarkdownHtmlGenerator.CreateFile(data);
7071
});
7172
}
72-
73-
private string CreateHtmlFile(string data)
74-
{
75-
//Generate the markup
76-
var markup = System.IO.File.ReadAllText("Markdown/markdown.html", Encoding.UTF8);
77-
78-
var tmp = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName() + ".html");
79-
using (var tmpStream = new System.IO.FileStream(tmp, System.IO.FileMode.Create))
80-
{
81-
var fs = new System.IO.StreamWriter(tmpStream, Encoding.UTF8);
82-
var dataIndex = markup.IndexOf("{{DATA}}", StringComparison.Ordinal);
83-
fs.Write(markup.Substring(0, dataIndex));
84-
fs.Write(data);
85-
fs.Write(markup.Substring(dataIndex + 8));
86-
fs.Flush();
87-
}
88-
return tmp;
89-
}
9073

9174
public void Init(NavObject navObject)
9275
{

CodeHub.iOS/CodeHub.iOS.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
<None Include="Entitlements.plist" />
215215
<Compile Include="Views\Repositories\RepositoriesTrendingView.cs" />
216216
<None Include="RELEASE-NOTES.txt" />
217+
<Compile Include="ViewControllers\MarkdownComposerViewController.cs" />
217218
</ItemGroup>
218219
<ItemGroup>
219220
<ProjectReference Include="..\lib\CodeFramework\CodeFramework.Core\CodeFramework.Core.iOS.csproj">
@@ -425,4 +426,7 @@
425426
<ITunesArtwork Include="iTunesArtwork%402x" />
426427
</ItemGroup>
427428
<ItemGroup />
429+
<ItemGroup>
430+
<Folder Include="ViewControllers\" />
431+
</ItemGroup>
428432
</Project>

CodeHub.iOS/Theme.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public static void Setup()
3636
UserVoice.UVStyleSheet.Instance.NavigationBarTextColor = UIColor.White;
3737

3838
UISegmentedControl.Appearance.TintColor = UIColor.FromRGB(110, 110, 117);
39+
UISegmentedControl.AppearanceWhenContainedIn(typeof(UINavigationController)).TintColor = UIColor.White;
40+
41+
// Composer Input Accessory Buttons
42+
UIButton.AppearanceWhenContainedIn(typeof(UIScrollView)).TintColor = UIColor.FromRGB(50, 50, 50);
43+
3944
UITableViewHeaderFooterView.Appearance.TintColor = UIColor.FromRGB(228, 228, 228);
4045
UILabel.AppearanceWhenContainedIn(typeof(UITableViewHeaderFooterView)).TextColor = UIColor.FromRGB(136, 136, 136);
4146
UILabel.AppearanceWhenContainedIn(typeof(UITableViewHeaderFooterView)).Font = UIFont.SystemFontOfSize(13f * Theme.CurrentTheme.FontSizeRatio);
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
using System;
2+
using CodeFramework.iOS.ViewControllers;
3+
using MonoTouch.UIKit;
4+
using Cirrious.CrossCore;
5+
using CodeHub.Core.Services;
6+
using CodeHub.Core.Utils;
7+
using MonoTouch.Foundation;
8+
using System.Net;
9+
using System.Collections.Specialized;
10+
using System.IO;
11+
using System.Threading.Tasks;
12+
using CodeFramework.Core.Services;
13+
14+
namespace CodeHub.iOS.ViewControllers
15+
{
16+
public class MarkdownComposerViewController : Composer
17+
{
18+
private readonly UISegmentedControl _viewSegment;
19+
private UIWebView _previewView;
20+
21+
public MarkdownComposerViewController()
22+
{
23+
_viewSegment = new UISegmentedControl(new [] { "Compose", "Preview" });
24+
_viewSegment.SelectedSegment = 0;
25+
NavigationItem.TitleView = _viewSegment;
26+
_viewSegment.ValueChanged += SegmentValueChanged;
27+
28+
var buttons = new []
29+
{
30+
CreateAccessoryButton("@", () => TextView.InsertText("@")),
31+
CreateAccessoryButton("#", () => TextView.InsertText("#")),
32+
CreateAccessoryButton("*", () => TextView.InsertText("*")),
33+
CreateAccessoryButton("`", () => TextView.InsertText("`")),
34+
CreateAccessoryButton("Image", () => {
35+
var range = TextView.SelectedRange;
36+
TextView.InsertText("![]()");
37+
TextView.SelectedRange = new MonoTouch.Foundation.NSRange(range.Location + 4, 0);
38+
}),
39+
CreateAccessoryButton("Upload", () => SelectImage()),
40+
CreateAccessoryButton("Link", () => {
41+
var range = TextView.SelectedRange;
42+
TextView.InsertText("[]()");
43+
TextView.SelectedRange = new MonoTouch.Foundation.NSRange(range.Location + 1, 0);
44+
}),
45+
CreateAccessoryButton("~", () => TextView.InsertText("~")),
46+
CreateAccessoryButton("=", () => TextView.InsertText("=")),
47+
CreateAccessoryButton("_", () => TextView.InsertText("_")),
48+
};
49+
50+
SetAccesoryButtons(buttons);
51+
}
52+
53+
private class ImagePickerDelegate : UINavigationControllerDelegate
54+
{
55+
public override void WillShowViewController(UINavigationController navigationController, UIViewController viewController, bool animated)
56+
{
57+
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
58+
}
59+
}
60+
61+
private class ImgurModel
62+
{
63+
public ImgurDataModel Data { get; set; }
64+
public bool Success { get; set; }
65+
66+
public class ImgurDataModel
67+
{
68+
public string Link { get; set; }
69+
}
70+
}
71+
72+
private async void UploadImage(UIImage img)
73+
{
74+
var hud = new CodeFramework.iOS.Utils.Hud(null);
75+
hud.Show("Uploading...");
76+
77+
try
78+
{
79+
var returnData = await Task.Run<byte[]>(() =>
80+
{
81+
using (var w = new WebClient())
82+
{
83+
var data = img.AsJPEG();
84+
byte[] dataBytes = new byte[data.Length];
85+
System.Runtime.InteropServices.Marshal.Copy(data.Bytes, dataBytes, 0, Convert.ToInt32(data.Length));
86+
87+
w.Headers.Set("Authorization", "Client-ID aa5d7d0bc1dffa6");
88+
89+
var values = new NameValueCollection
90+
{
91+
{ "image", Convert.ToBase64String(dataBytes) }
92+
};
93+
94+
return w.UploadValues("https://api.imgur.com/3/image", values);
95+
}
96+
});
97+
98+
99+
var json = Mvx.Resolve<IJsonSerializationService>();
100+
var imgurModel = json.Deserialize<ImgurModel>(System.Text.Encoding.UTF8.GetString(returnData));
101+
TextView.InsertText("![](" + imgurModel.Data.Link + ")");
102+
}
103+
catch (Exception e)
104+
{
105+
MonoTouch.Utilities.ShowAlert("Error", "Unable to upload image: " + e.Message);
106+
}
107+
finally
108+
{
109+
hud.Hide();
110+
}
111+
}
112+
113+
private void SelectImage()
114+
{
115+
var imagePicker = new UIImagePickerController();
116+
imagePicker.NavigationControllerDelegate = new ImagePickerDelegate();
117+
imagePicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
118+
imagePicker.MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary);
119+
imagePicker.FinishedPickingMedia += (object sender, UIImagePickerMediaPickedEventArgs e) =>
120+
{
121+
// determine what was selected, video or image
122+
bool isImage = false;
123+
switch(e.Info[UIImagePickerController.MediaType].ToString()) {
124+
case "public.image":
125+
Console.WriteLine("Image selected");
126+
isImage = true;
127+
break;
128+
case "public.video":
129+
Console.WriteLine("Video selected");
130+
break;
131+
}
132+
133+
// get common info (shared between images and video)
134+
NSUrl referenceURL = e.Info[new NSString("UIImagePickerControllerReferenceUrl")] as NSUrl;
135+
if (referenceURL != null)
136+
Console.WriteLine("Url:"+referenceURL.ToString ());
137+
138+
// if it was an image, get the other image info
139+
if(isImage) {
140+
// get the original image
141+
UIImage originalImage = e.Info[UIImagePickerController.OriginalImage] as UIImage;
142+
if(originalImage != null) {
143+
// do something with the image
144+
try
145+
{
146+
UploadImage(originalImage);
147+
}
148+
catch (Exception ex)
149+
{
150+
Console.WriteLine("Fudge...");
151+
}
152+
Console.WriteLine ("got the original image");
153+
//imageView.Image = originalImage; // display
154+
}
155+
} else { // if it's a video
156+
//TODO: Don't support video...
157+
}
158+
159+
// dismiss the picker
160+
imagePicker.DismissViewController(true, null);
161+
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
162+
};
163+
164+
165+
imagePicker.Canceled += (object sender, EventArgs e) =>
166+
{
167+
imagePicker.DismissViewController(true, null);
168+
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
169+
};
170+
171+
NavigationController.PresentViewController(imagePicker, true, null);
172+
}
173+
174+
void SegmentValueChanged (object sender, EventArgs e)
175+
{
176+
if (_viewSegment.SelectedSegment == 0)
177+
{
178+
if (_previewView != null)
179+
{
180+
_previewView.RemoveFromSuperview();
181+
_previewView.Dispose();
182+
_previewView = null;
183+
}
184+
185+
Add(TextView);
186+
TextView.BecomeFirstResponder();
187+
}
188+
else
189+
{
190+
if (_previewView == null)
191+
_previewView = new UIWebView(this.View.Bounds);
192+
193+
TextView.RemoveFromSuperview();
194+
Add(_previewView);
195+
196+
var markdownService = Mvx.Resolve<IMarkdownService>();
197+
var path = MarkdownHtmlGenerator.CreateFile(markdownService.Convert(Text));
198+
var uri = Uri.EscapeUriString("file://" + path) + "#" + Environment.TickCount;
199+
_previewView.LoadRequest(new MonoTouch.Foundation.NSUrlRequest(new MonoTouch.Foundation.NSUrl(uri)));
200+
}
201+
}
202+
}
203+
}
204+

CodeHub.iOS/Views/Issues/IssueEditView.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using MonoTouch.UIKit;
77
using CodeHub.Core.ViewModels.Issues;
88
using CodeFramework.iOS.Utils;
9+
using CodeHub.iOS.ViewControllers;
910

1011
namespace CodeHub.iOS.Views.Issues
1112
{
@@ -45,7 +46,7 @@ public override void ViewDidLoad()
4546
var content = new MultilinedElement("Description");
4647
content.Tapped += () =>
4748
{
48-
var composer = new Composer { Title = "Issue Description", Text = content.Value };
49+
var composer = new MarkdownComposerViewController { Title = "Issue Description", Text = content.Value };
4950
composer.NewComment(this, (text) => {
5051
vm.Content = text;
5152
composer.CloseComposer();

CodeHub.iOS/Views/Issues/IssueView.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using CodeFramework.iOS.Elements;
99
using System.Linq;
1010
using System.Collections.Generic;
11+
using CodeHub.iOS.ViewControllers;
1112

1213
namespace CodeHub.iOS.Views.Issues
1314
{
@@ -132,16 +133,16 @@ private static string CreateEventBody(string eventType, string commitId)
132133
public void RenderComments()
133134
{
134135
var s = Cirrious.CrossCore.Mvx.Resolve<CodeFramework.Core.Services.IJsonSerializationService>();
135-
136-
var data = s.Serialize(CreateCommentList().Select(x => new {
136+
var comments = CreateCommentList().Select(x => new {
137137
avatarUrl = x.AvatarUrl,
138138
login = x.Login,
139139
created_at = x.CreatedAt.ToDaysAgo(),
140140
body = x.Body
141-
}));
141+
});
142+
var data = s.Serialize(comments);
142143

143144
InvokeOnMainThread(() => {
144-
_commentsElement.Value = data;
145+
_commentsElement.Value = !comments.Any() ? string.Empty : data;
145146
if (_commentsElement.GetImmediateRootElement() == null)
146147
Render();
147148
});
@@ -174,7 +175,7 @@ protected virtual void Render()
174175

175176
void AddCommentTapped()
176177
{
177-
var composer = new Composer();
178+
var composer = new MarkdownComposerViewController();
178179
composer.NewComment(this, async (text) => {
179180
try
180181
{

0 commit comments

Comments
 (0)