summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2012-02-12 01:53:36 +0400
committerGravatar Vitaly Takmazov2012-02-12 01:53:36 +0400
commit6a92a6a4d27dc07f8b32bd7d57ffbcbe15630ab9 (patch)
treecf62fc48a13eb5b8744b361acf47bdcd820751a1
parent49eb44f852ab21e72c17bbc436ffa79525a1aba3 (diff)
Avatars support + broken clickable urls
-rw-r--r--Juick/App.xaml.cs6
-rw-r--r--Juick/Classes/RichTextConverter.cs58
-rw-r--r--Juick/Juick.csproj2
-rw-r--r--Juick/MainPage.xaml58
-rw-r--r--Juick/MainPage.xaml.cs44
-rw-r--r--Juick/ThreadView.xaml23
-rw-r--r--Juick/ViewModels/MainViewModel.cs76
-rw-r--r--Juick/ViewModels/MessageViewModel.cs8
-rw-r--r--Juick/ViewModels/ThreadViewModel.cs19
9 files changed, 242 insertions, 52 deletions
diff --git a/Juick/App.xaml.cs b/Juick/App.xaml.cs
index 54abe20..b73398c 100644
--- a/Juick/App.xaml.cs
+++ b/Juick/App.xaml.cs
@@ -39,6 +39,12 @@ namespace Juick
get { return _cl ?? (_cl = new RestClient("http://api.juick.com") {UserAgent = "Juick 0.999/Windows Phone " + Environment.OSVersion.Version}); }
}
+ private static RestClient _acl;
+ public static RestClient AvatarClient
+ {
+ get { return _acl ?? (_acl = new RestClient("http://i.juick.com") { UserAgent = "Juick 0.999/Windows Phone " + Environment.OSVersion.Version }); }
+ }
+
/// <summary>
/// Provides easy access to the root frame of the Phone Application.
/// </summary>
diff --git a/Juick/Classes/RichTextConverter.cs b/Juick/Classes/RichTextConverter.cs
new file mode 100644
index 0000000..ee6ffa7
--- /dev/null
+++ b/Juick/Classes/RichTextConverter.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Tasks;
+
+namespace Juick.Classes
+{
+ public class RichTextConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var message = value as string;
+ var runs = new List<Inline>();
+
+ foreach (var word in message.Split(new char[] {' ', '\n'}))
+ {
+ Uri uri;
+
+ if (Uri.TryCreate(word, UriKind.Absolute, out uri) ||
+ (word.StartsWith("www.") && Uri.TryCreate("http://" + word, UriKind.Absolute, out uri)))
+ {
+ var link = new Hyperlink();
+ link.Inlines.Add(new Run() { Text = word });
+ link.Click += (sender, e) =>
+ {
+ var hyperLink = (sender as Hyperlink);
+ new WebBrowserTask() { Uri = uri }.Show();
+ };
+
+ runs.Add(link);
+ }
+ else
+ {
+ runs.Add(new Run() { Text = word });
+ }
+
+ runs.Add(new Run() { Text = " " });
+ }
+
+ return runs;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value;
+ }
+ }
+}
diff --git a/Juick/Juick.csproj b/Juick/Juick.csproj
index e550947..73d65c1 100644
--- a/Juick/Juick.csproj
+++ b/Juick/Juick.csproj
@@ -71,6 +71,7 @@
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Classes\AccountManager.cs" />
+ <Compile Include="Classes\RichTextConverter.cs" />
<Compile Include="LoginView.xaml.cs">
<DependentUpon>LoginView.xaml</DependentUpon>
</Compile>
@@ -125,7 +126,6 @@
<Content Include="Background.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Resource Include="wp7.jpg" />
<Resource Include="PanoramaBackground.png" />
<Content Include="SplashScreenImage.jpg" />
</ItemGroup>
diff --git a/Juick/MainPage.xaml b/Juick/MainPage.xaml
index 3d7245c..84e7bd7 100644
--- a/Juick/MainPage.xaml
+++ b/Juick/MainPage.xaml
@@ -6,14 +6,19 @@
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="728"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:bindings="clr-namespace:Juick.Classes"
+ xmlns:Juick="clr-namespace:Juick" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="728"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
+ <FrameworkElement.Resources>
+ <ResourceDictionary>
+ <bindings:RichTextConverter x:Key="inlineConverter" />
+ </ResourceDictionary>
+ </FrameworkElement.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
@@ -26,10 +31,15 @@
<controls:PanoramaItem x:Name="MainPanoramaItem" Header="My feed" Margin="0, -40, 0, 0">
<!--Double line list with image placeholder and text wrapping-->
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding MyFeed}" SelectionChanged="ListBoxSelectionChanged">
+ <ListBox.ItemContainerStyle>
+ <Style TargetType="ListBoxItem">
+ <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
+ </Style>
+ </ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
- <Grid >
-
+ <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1">
+ <Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -39,24 +49,28 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
- <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
+ <Image Source="{Binding UserAvatar}" Grid.Row="0" Grid.Column="0" Margin="3" />
+ <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
Margin="5,0,5,5" VerticalAlignment="Top"
HorizontalAlignment="Left"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Style="{StaticResource PhoneTextAccentStyle}" />
- <TextBlock Text="{Binding MessageText}" Grid.Row="1" Grid.Column="1"
+ <!-- Juick:MainPage.InlineList="{Binding MessageText, Converter={StaticResource inlineConverter}}" -->
+ <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
+ Text="{Binding MessageText}"
Foreground="{StaticResource PhoneForegroundBrush}"
Style="{StaticResource PhoneTextNormalStyle}"
Margin="5,0,5,5" VerticalAlignment="Top"
TextWrapping="Wrap" HorizontalAlignment="Left"/>
- <TextBlock Text="{Binding Status}" Grid.Row="2" Grid.Column="1"
+ <TextBlock Text="{Binding Status}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
Foreground="{StaticResource PhoneForegroundBrush}"
Style="{StaticResource PhoneTextAccentStyle}"
FontSize="{StaticResource PhoneFontSizeSmall}"
Margin="5,0,5,5" VerticalAlignment="Top"
TextWrapping="Wrap" HorizontalAlignment="Left"/>
- </Grid>
+ </Grid>
+ </Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@@ -64,8 +78,14 @@
<controls:PanoramaItem x:Name="LastPanoramaItem" Header="Last" Margin="0, -40, 0, 0">
<!--Double line list with image placeholder and text wrapping-->
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Last}" SelectionChanged="LastBoxSelectionChanged">
+ <ListBox.ItemContainerStyle>
+ <Style TargetType="ListBoxItem">
+ <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
+ </Style>
+ </ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
+ <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -76,26 +96,26 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
- <Image Source="{Binding UserAvatar}" Grid.Row="0" Grid.Column="0" />
- <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
+ <Image Source="{Binding UserAvatar}" Grid.Row="0" Grid.Column="0" Margin="3" />
+ <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
Margin="5,0,5,5" VerticalAlignment="Top"
HorizontalAlignment="Left"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Style="{StaticResource PhoneTextAccentStyle}" />
- <TextBlock Text="{Binding MessageText}" Grid.Row="1" Grid.Column="1"
+ <TextBlock Text="{Binding MessageText}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Foreground="{StaticResource PhoneForegroundBrush}"
Style="{StaticResource PhoneTextNormalStyle}"
Margin="5,0,5,5" VerticalAlignment="Top"
TextWrapping="Wrap" HorizontalAlignment="Left"/>
- <TextBlock Text="{Binding Status}" Grid.Row="2" Grid.Column="1"
+ <TextBlock Text="{Binding Status}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
Foreground="{StaticResource PhoneForegroundBrush}"
Style="{StaticResource PhoneTextAccentStyle}"
FontSize="{StaticResource PhoneFontSizeSmall}"
Margin="5,0,5,5" VerticalAlignment="Top"
TextWrapping="Wrap" HorizontalAlignment="Left"/>
</Grid>
-
+ </Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
@@ -104,14 +124,14 @@
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
- <shell:ApplicationBarIconButton IconUri="/Images/appbar_button0.png" Text="New message" Click="ApplicationBarIconButton_Click_1"/>
- <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Refresh" Click="ApplicationBarIconButton_Click" />
- <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Sign out" Click="ApplicationBarMenuItem_Click" />
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button0.png" Text="New message" Click="ApplicationBarIconButtonClick1"/>
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Refresh" Click="ApplicationBarIconButtonClick" />
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Sign out" Click="ApplicationBarMenuItemClick" />
<shell:ApplicationBar.MenuItems>
- <shell:ApplicationBarMenuItem Text="New message" Click="ApplicationBarIconButton_Click_1"/>
- <shell:ApplicationBarMenuItem Text="Refresh" Click="ApplicationBarIconButton_Click"/>
- <shell:ApplicationBarMenuItem Text="Sign out" Click="ApplicationBarMenuItem_Click" />
+ <shell:ApplicationBarMenuItem Text="New message" Click="ApplicationBarIconButtonClick1"/>
+ <shell:ApplicationBarMenuItem Text="Refresh" Click="ApplicationBarIconButtonClick"/>
+ <shell:ApplicationBarMenuItem Text="Sign out" Click="ApplicationBarMenuItemClick" />
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
diff --git a/Juick/MainPage.xaml.cs b/Juick/MainPage.xaml.cs
index 4468f6a..1654c1b 100644
--- a/Juick/MainPage.xaml.cs
+++ b/Juick/MainPage.xaml.cs
@@ -64,19 +64,57 @@ namespace Juick
((ListBox)sender).SelectedIndex = -1;
}
- private void ApplicationBarIconButton_Click(object sender, EventArgs e)
+ public static string GetInlineList(TextBlock element)
+ {
+ if (element != null)
+ return element.GetValue(InlineList) as string;
+ return string.Empty;
+ }
+
+ public static void SetInlineList(TextBlock element, string value)
+ {
+ if (element != null)
+ element.SetValue(InlineList, value);
+ }
+
+ public static readonly DependencyProperty InlineList =
+ DependencyProperty.RegisterAttached(
+ "InlineList",
+ typeof(List<Inline>),
+ typeof(MainPage),
+ new PropertyMetadata(null, OnInlineListPropertyChanged));
+
+ private static void OnInlineListPropertyChanged(DependencyObject obj,
+ DependencyPropertyChangedEventArgs e)
+ {
+ var tb = obj as TextBlock;
+ if (tb != null)
+ {
+ // clear previous inlines
+ tb.Inlines.Clear();
+
+ // add new inlines
+ var inlines = e.NewValue as List<Inline>;
+ if (inlines != null)
+ {
+ inlines.ForEach(inl => tb.Inlines.Add((inl)));
+ }
+ }
+ }
+
+ private void ApplicationBarIconButtonClick(object sender, EventArgs e)
{
App.ViewModel.MyFeed.Clear();
App.ViewModel.Last.Clear();
App.ViewModel.LoadData();
}
- private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
+ private void ApplicationBarMenuItemClick(object sender, EventArgs e)
{
App.Account.SignOut(this);
}
- private void ApplicationBarIconButton_Click_1(object sender, EventArgs e)
+ private void ApplicationBarIconButtonClick1(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/NewPostView.xaml", UriKind.Relative));
}
diff --git a/Juick/ThreadView.xaml b/Juick/ThreadView.xaml
index 20529c2..2decd6e 100644
--- a/Juick/ThreadView.xaml
+++ b/Juick/ThreadView.xaml
@@ -28,9 +28,15 @@
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="ListBox_SelectionChanged">
+ <ListBox.ItemContainerStyle>
+ <Style TargetType="ListBoxItem">
+ <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
+ </Style>
+ </ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
- <Grid>
+ <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1">
+ <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -40,20 +46,21 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
- <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
+ <Image Source="{Binding UserAvatar}" Grid.Row="0" Grid.Column="0" Margin="3" />
+
+ <TextBlock Text="{Binding Username}" Grid.Row="0" Grid.Column="1"
Margin="5,0,5,5" VerticalAlignment="Top"
- HorizontalAlignment="Left"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
FontSize="{StaticResource PhoneFontSizeLarge}"
- Style="{StaticResource PhoneTextAccentStyle}" />
- <TextBlock Text="{Binding MessageText}" Grid.Row="1" Grid.Column="1"
+ Style="{StaticResource PhoneTextAccentStyle}" HorizontalAlignment="Left"/>
+ <TextBlock Text="{Binding MessageText}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Foreground="{StaticResource PhoneForegroundBrush}"
-
+ HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}"
Margin="5,0,5,5" VerticalAlignment="Top"
- TextWrapping="Wrap" HorizontalAlignment="Left"/>
+ TextWrapping="Wrap" />
</Grid>
-
+ </Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
diff --git a/Juick/ViewModels/MainViewModel.cs b/Juick/ViewModels/MainViewModel.cs
index a504658..23ff020 100644
--- a/Juick/ViewModels/MainViewModel.cs
+++ b/Juick/ViewModels/MainViewModel.cs
@@ -2,10 +2,13 @@
using System.ComponentModel;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Collections.ObjectModel;
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
using Juick.Api;
using RestSharp;
@@ -52,16 +55,36 @@ namespace Juick.ViewModels
var ser = new DataContractJsonSerializer(typeof (List<Message>));
var messages =
- (List<Message>)ser.ReadObject(new MemoryStream(response.RawBytes));
+ ser.ReadObject(new MemoryStream(response.RawBytes)) as List<Message>;
MyFeed.Clear();
- messages.ForEach(post => MyFeed.Add(new MessageViewModel(post)
- {
- Status =
- string.Format(
- "Posted on: {0}, replies: {1}",
- post.timestamp,
- post.replies)
- }));
+ messages.ForEach(post =>
+ {
+ var item = new MessageViewModel(post)
+ {
+ Status =
+ string.Format(
+ "Posted on: {0}, replies: {1}",
+ post.
+ timestamp,
+ post.
+ replies)
+ };
+ MyFeed.Add(item);
+ var imageRequest =
+ new RestRequest(
+ string.Format("/as/{0}.png",
+ post.user.uid));
+ App.AvatarClient.ExecuteAsync(
+ imageRequest, restResponse =>
+ {
+ item.UserAvatar = new BitmapImage
+ ();
+ item.UserAvatar.SetSource(new MemoryStream(restResponse.RawBytes));
+ item.
+ NotifyPropertyChanged
+ ("UserAvatar");
+ });
+ });
NotifyPropertyChanged("MyFeed");
});
@@ -75,13 +98,34 @@ namespace Juick.ViewModels
(List<Message>)ser.ReadObject(ms);
if (messages == null) return;
Last.Clear();
- messages.ForEach(post => Last.Add(new MessageViewModel(post)
+ messages.ForEach(post =>
{
- Status = string.Format(
- "Posted on: {0}, replies: {1}",
- post.timestamp, post.replies
- )
- }));
+ var item = new MessageViewModel(post)
+ {
+ Status =
+ string.Format(
+ "Posted on: {0}, replies: {1}",
+ post.
+ timestamp,
+ post.
+ replies)
+ };
+ Last.Add(item);
+ var imageRequest =
+ new RestRequest(
+ string.Format("/as/{0}.png",
+ post.user.uid));
+ App.AvatarClient.ExecuteAsync(
+ imageRequest, restResponse =>
+ {
+ item.UserAvatar = new BitmapImage
+ ();
+ item.UserAvatar.SetSource(new MemoryStream(restResponse.RawBytes));
+ item.
+ NotifyPropertyChanged
+ ("UserAvatar");
+ });
+ });
NotifyPropertyChanged("Last");
}
});
@@ -89,7 +133,7 @@ namespace Juick.ViewModels
public event PropertyChangedEventHandler PropertyChanged;
- private void NotifyPropertyChanged(String propertyName)
+ public void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
diff --git a/Juick/ViewModels/MessageViewModel.cs b/Juick/ViewModels/MessageViewModel.cs
index 32da0aa..8620ab3 100644
--- a/Juick/ViewModels/MessageViewModel.cs
+++ b/Juick/ViewModels/MessageViewModel.cs
@@ -9,6 +9,7 @@ using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
+using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Juick.Api;
@@ -90,8 +91,8 @@ namespace Juick
}
}
- private Image _avatar;
- public Image UserAvatar
+ private BitmapImage _avatar;
+ public BitmapImage UserAvatar
{
get { return _avatar; }
set
@@ -147,7 +148,8 @@ namespace Juick
}
public event PropertyChangedEventHandler PropertyChanged;
- private void NotifyPropertyChanged(String propertyName)
+
+ public void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
diff --git a/Juick/ViewModels/ThreadViewModel.cs b/Juick/ViewModels/ThreadViewModel.cs
index 48ebe65..bff72b7 100644
--- a/Juick/ViewModels/ThreadViewModel.cs
+++ b/Juick/ViewModels/ThreadViewModel.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Net;
using System.Net.Browser;
using System.Runtime.Serialization.Json;
+using System.Windows.Media.Imaging;
using Juick.Api;
using RestSharp;
@@ -48,8 +49,22 @@ namespace Juick.ViewModels
Items.Clear();
messages.ForEach(post =>
{
- this.Items.Add(
- new MessageViewModel(post));
+ var item = new MessageViewModel(post);
+ Items.Add(item);
+ var imageRequest =
+ new RestRequest(
+ string.Format("/as/{0}.png",
+ post.user.uid));
+ App.AvatarClient.ExecuteAsync(
+ imageRequest, restResponse =>
+ {
+ item.UserAvatar = new BitmapImage
+ ();
+ item.UserAvatar.SetSource(new MemoryStream(restResponse.RawBytes));
+ item.
+ NotifyPropertyChanged
+ ("UserAvatar");
+ });
});
IsDataLoaded = true;
NotifyPropertyChanged("Items");