diff options
-rw-r--r-- | Juick/App.xaml | 19 | ||||
-rw-r--r-- | Juick/Classes/AccountManager.cs | 40 | ||||
-rw-r--r-- | Juick/Classes/BooleanToVisibiltyConverter.cs | 24 | ||||
-rw-r--r-- | Juick/Classes/DateHelper.cs | 67 | ||||
-rw-r--r-- | Juick/Controls/MessageList.xaml | 45 | ||||
-rw-r--r-- | Juick/DataTemplates/PostItemDataTemplate.xaml | 44 | ||||
-rw-r--r-- | Juick/Juick.csproj | 13 | ||||
-rw-r--r-- | Juick/LoginView.xaml | 3 | ||||
-rw-r--r-- | Juick/MainPage.xaml.cs | 2 | ||||
-rw-r--r-- | Juick/NewPostView.xaml | 2 | ||||
-rw-r--r-- | Juick/Properties/AssemblyInfo.cs | 4 | ||||
-rw-r--r-- | Juick/SampleData/ThreadViewModelSampleData.xaml | 16 | ||||
-rw-r--r-- | Juick/ThreadView.xaml | 147 | ||||
-rw-r--r-- | Juick/ViewModels/AppViewModel.cs | 94 | ||||
-rw-r--r-- | Juick/ViewModels/LoginViewModel.cs | 6 | ||||
-rw-r--r-- | Juick/ViewModels/NewPostViewModel.cs | 28 | ||||
-rw-r--r-- | Juick/ViewModels/PostItem.cs | 9 |
17 files changed, 315 insertions, 248 deletions
diff --git a/Juick/App.xaml b/Juick/App.xaml index 0c60cc0..1b67f8c 100644 --- a/Juick/App.xaml +++ b/Juick/App.xaml @@ -1,20 +1,25 @@ -<Application
- x:Class="Juick.App"
+<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
- xmlns:sys="clr-namespace:System;assembly=mscorlib">
+ xmlns:sys="clr-namespace:System;assembly=mscorlib"
+ x:Class="Juick.App"
+ >
- <!--Application Resources-->
<Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="DataTemplates/PostItemDataTemplate.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
</Application.Resources>
<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
- <shell:PhoneApplicationService
- Launching="Application_Launching" Closing="Application_Closing"
- Activated="Application_Activated" Deactivated="Application_Deactivated"/>
+ <shell:PhoneApplicationService
+ Launching="Application_Launching" Closing="Application_Closing"
+ Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>
</Application>
\ No newline at end of file diff --git a/Juick/Classes/AccountManager.cs b/Juick/Classes/AccountManager.cs index 1f9ffe5..eb99d92 100644 --- a/Juick/Classes/AccountManager.cs +++ b/Juick/Classes/AccountManager.cs @@ -3,6 +3,8 @@ using System.IO.IsolatedStorage; using System.Net;
using System.Windows;
using System.Windows.Controls;
+using RestSharp;
+using System.Diagnostics;
namespace Juick.Classes
{
@@ -10,14 +12,14 @@ namespace Juick.Classes {
private string _userName;
private string _password;
-
+
public string UserName
{
get
{
if (_userName == null)
{
- IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("user", out _userName);
+ IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("user", out _userName);
}
return _userName;
}
@@ -34,7 +36,7 @@ namespace Juick.Classes {
if (_password == null)
{
- IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("password", out _password);
+ IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("password", out _password);
}
return _password;
}
@@ -47,7 +49,8 @@ namespace Juick.Classes public bool IsAuthenticated
{
- get {
+ get
+ {
bool authenticated;
IsolatedStorageSettings.ApplicationSettings.TryGetValue<bool>("authenticated", out authenticated);
return authenticated;
@@ -55,26 +58,45 @@ namespace Juick.Classes set { IsolatedStorageSettings.ApplicationSettings["authenticated"] = value; }
}
+
+
public string NotificationUri
{
get
{
- string savedUri;
- IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("notification_uri", out savedUri);
- return savedUri;
+ string _notificationUri;
+ IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("notification_uri", out _notificationUri);
+ return _notificationUri;
}
set
{
+ var oldValue = NotificationUri;
+ if (!string.IsNullOrEmpty(oldValue))
+ UnregisterNotificationUrl(oldValue);
IsolatedStorageSettings.ApplicationSettings["notification_uri"] = value;
+ if (!string.IsNullOrEmpty(value))
+ RegisterNotificationUrl(value);
}
}
-
-
+
+
public void SignOut(Page page)
{
IsAuthenticated = false;
+ App.AppContext.DisableNotifications();
page.NavigationService.Navigate(new Uri("/LoginView.xaml", UriKind.Relative));
page.Dispatcher.BeginInvoke(() => page.NavigationService.RemoveBackEntry());
}
+
+ void RegisterNotificationUrl(string newUrl)
+ {
+ App.AppContext.Client.ExecuteAsync(new RestRequest("/winphone/register?url=" + newUrl),
+ response => Debug.WriteLine("Registering push url, status {0}: {1}", response.Request.Resource, response.StatusCode));
+ }
+ void UnregisterNotificationUrl(string oldUrl)
+ {
+ App.AppContext.Client.ExecuteAsync(new RestRequest("/winphone/unregister?url=" + oldUrl),
+ response => Debug.WriteLine("Unregistered push url, status {0}: {1}", response.Request.Resource, response.StatusCode));
+ }
}
}
diff --git a/Juick/Classes/BooleanToVisibiltyConverter.cs b/Juick/Classes/BooleanToVisibiltyConverter.cs deleted file mode 100644 index 679cc3f..0000000 --- a/Juick/Classes/BooleanToVisibiltyConverter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Data; - -namespace Juick.Classes -{ - public class BooleanToVisibiltyConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var visible = (bool) value; - return visible ? Visibility.Visible : Visibility.Collapsed; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} diff --git a/Juick/Classes/DateHelper.cs b/Juick/Classes/DateHelper.cs new file mode 100644 index 0000000..072c56a --- /dev/null +++ b/Juick/Classes/DateHelper.cs @@ -0,0 +1,67 @@ +using System; +using System.Net; +using System.Windows; +using System.Windows.Controls; +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 System.Globalization; + +namespace Juick.Classes +{ + public class DateHelper + { + public static string PrettyDate(DateTime dateTime) + { + var timeSpan = DateTime.Now - dateTime; + + // span is less than or equal to 60 seconds, measure in seconds. + if (timeSpan <= TimeSpan.FromSeconds(60)) + { + return timeSpan.Seconds > 5 + ? "about " + timeSpan.Seconds + " seconds ago" + : "just now"; + } + + // span is less than or equal to 60 minutes, measure in minutes. + if (timeSpan <= TimeSpan.FromMinutes(60)) + { + return timeSpan.Minutes > 1 + ? "about " + timeSpan.Minutes + " minutes ago" + : "about a minute ago"; + } + + // span is less than or equal to 24 hours, measure in hours. + if (timeSpan <= TimeSpan.FromHours(24)) + { + return timeSpan.Hours > 1 + ? "about " + timeSpan.Hours + " hours ago" + : "about an hour ago"; + } + + // span is less than or equal to 30 days (1 month), measure in days. + if (timeSpan <= TimeSpan.FromDays(30)) + { + return timeSpan.Days > 1 + ? "about " + timeSpan.Days + " days ago" + : "about a day ago"; + } + + // span is less than or equal to 365 days (1 year), measure in months. + if (timeSpan <= TimeSpan.FromDays(365)) + { + return timeSpan.Days > 30 + ? "about " + timeSpan.Days / 30 + " months ago" + : "about a month ago"; + } + + // span is greater than 365 days (1 year), measure in years. + return timeSpan.Days > 365 + ? "about " + timeSpan.Days / 365 + " years ago" + : "about a year ago"; + } + } +} diff --git a/Juick/Controls/MessageList.xaml b/Juick/Controls/MessageList.xaml index afa6c69..ac6db00 100644 --- a/Juick/Controls/MessageList.xaml +++ b/Juick/Controls/MessageList.xaml @@ -12,10 +12,10 @@ FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" d:DesignHeight="480" d:DesignWidth="480"> - + <Grid x:Name="LayoutRoot"> <toolkit:LongListSelector Margin="0, 0, -12, 0" - ItemsSource="{Binding Items}" IsFlatList="true"> + ItemsSource="{Binding Items}" IsFlatList="true" ItemTemplate="{StaticResource PostItemDataTemplate}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Link"> <bindings:InvokeDelegateCommandAction Command="{Binding LoadMessagesPageCommand}" @@ -25,46 +25,7 @@ <bindings:InvokeDelegateCommandAction Command="{Binding NavigateNextCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=InvokeParameter}"/> </i:EventTrigger> - </i:Interaction.Triggers> - <toolkit:LongListSelector.ItemTemplate> - <DataTemplate> - <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Image bindings:LowProfileImageLoader.UriSource="{Binding AvatarUri}" 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}" /> - <!--Style="{StaticResource PhoneTextNormalStyle}"--> - <usercontrols:HyperLinkRichTextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" - TextWrapping="Wrap" HorizontalAlignment="Left" - Foreground="{StaticResource PhoneForegroundBrush}" - Margin="5,0,5,5" VerticalAlignment="Top" - IsReadOnly="True" Text="{Binding MessageText}" /> - <Image bindings:LowProfileImageLoader.UriSource="{Binding Attachment}" Grid.Row="2" Grid.Column="0" Margin="3" Grid.ColumnSpan="2" /> - <TextBlock Text="{Binding Status}" Grid.Row="3" 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> - </toolkit:LongListSelector.ItemTemplate> + </i:Interaction.Triggers> </toolkit:LongListSelector> </Grid> </UserControl> diff --git a/Juick/DataTemplates/PostItemDataTemplate.xaml b/Juick/DataTemplates/PostItemDataTemplate.xaml new file mode 100644 index 0000000..4668a48 --- /dev/null +++ b/Juick/DataTemplates/PostItemDataTemplate.xaml @@ -0,0 +1,44 @@ +<ResourceDictionary + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:bindings="clr-namespace:Juick.Classes" + xmlns:usercontrols="clr-namespace:Juick.Controls" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > + + <DataTemplate x:Key="PostItemDataTemplate"> + <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <Image bindings:LowProfileImageLoader.UriSource="{Binding AvatarUri}" 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}" /> + <usercontrols:HyperLinkRichTextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" + TextWrapping="Wrap" HorizontalAlignment="Left" + Foreground="{StaticResource PhoneForegroundBrush}" + Margin="5,0,5,5" VerticalAlignment="Top" + IsReadOnly="True" Text="{Binding MessageText}" /> + <Image bindings:LowProfileImageLoader.UriSource="{Binding Attachment}" Grid.Row="2" Grid.Column="0" Margin="3" + Grid.ColumnSpan="2" /> + <TextBlock Text="{Binding Status}" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" + Foreground="{StaticResource PhoneForegroundBrush}" + Style="{StaticResource PhoneTextAccentStyle}" + FontSize="{StaticResource PhoneFontSizeSmall}" + Margin="5,0,5,5" VerticalAlignment="Top" + TextWrapping="NoWrap" TextAlignment="Right"/> + </Grid> + </Border> + + </DataTemplate> +</ResourceDictionary>
\ No newline at end of file diff --git a/Juick/Juick.csproj b/Juick/Juick.csproj index 0163f65..c89c775 100644 --- a/Juick/Juick.csproj +++ b/Juick/Juick.csproj @@ -27,6 +27,8 @@ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
+ <Utf8Output>true</Utf8Output>
+ <ExpressionBlendVersion>4.0.30816.0</ExpressionBlendVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -109,7 +111,6 @@ <Compile Include="ViewModels\PageViewModel.cs" />
<Compile Include="ViewModels\PostItem.cs" />
<Compile Include="ViewModels\ThreadViewModel.cs" />
- <Compile Include="ViewModels\Validation\DataViewModelBase.cs" />
<Compile Include="ViewModels\ViewModelBase.cs" />
</ItemGroup>
<ItemGroup>
@@ -121,6 +122,10 @@ <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="DataTemplates\PostItemDataTemplate.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="LoginView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -192,6 +197,12 @@ <Content Include="Images\appbar.send.png" />
<Content Include="SplashScreenImage.jpg" />
</ItemGroup>
+ <ItemGroup>
+ <DesignData Include="SampleData\ThreadViewModelSampleData.xaml">
+ <Generator>MSBuild:MarkupCompilePass1</Generator>
+ </DesignData>
+ </ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/Juick/LoginView.xaml b/Juick/LoginView.xaml index 004580a..3e204a4 100644 --- a/Juick/LoginView.xaml +++ b/Juick/LoginView.xaml @@ -9,10 +9,9 @@ xmlns:viewModels="clr-namespace:Juick.ViewModels"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
- Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
- phoneshell:SystemTray.IsVisible="True">
+ phoneshell:SystemTray.IsVisible="True" CacheMode="BitmapCache">
<phone:PhoneApplicationPage.DataContext>
<viewModels:LoginViewModel />
</phone:PhoneApplicationPage.DataContext>
diff --git a/Juick/MainPage.xaml.cs b/Juick/MainPage.xaml.cs index 20beef5..7baa6dd 100644 --- a/Juick/MainPage.xaml.cs +++ b/Juick/MainPage.xaml.cs @@ -70,7 +70,7 @@ namespace Juick }
if (!string.IsNullOrEmpty(FileId) || navigateUri.StartsWith(loginUriPart))
{
- NavigationService.Navigate(new Uri(navigateUri, UriKind.Relative));
+ ((App)Application.Current).NavigateTo(new Uri(navigateUri, UriKind.Relative), true);
}
if (queryStrings.ContainsKey("mid"))
{
diff --git a/Juick/NewPostView.xaml b/Juick/NewPostView.xaml index f3a911b..1ed01b5 100644 --- a/Juick/NewPostView.xaml +++ b/Juick/NewPostView.xaml @@ -11,7 +11,7 @@ Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
- shell:SystemTray.IsVisible="True">
+ shell:SystemTray.IsVisible="True" CacheMode="BitmapCache">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
diff --git a/Juick/Properties/AssemblyInfo.cs b/Juick/Properties/AssemblyInfo.cs index d97b9eb..7d007ab 100644 --- a/Juick/Properties/AssemblyInfo.cs +++ b/Juick/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ using System.Resources; //
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.1.0.2")]
-[assembly: AssemblyFileVersion("1.1.0.2")]
+[assembly: AssemblyVersion("1.1.0")]
+[assembly: AssemblyFileVersion("1.1.0")]
[assembly: NeutralResourcesLanguageAttribute("en-US")]
diff --git a/Juick/SampleData/ThreadViewModelSampleData.xaml b/Juick/SampleData/ThreadViewModelSampleData.xaml new file mode 100644 index 0000000..784bee3 --- /dev/null +++ b/Juick/SampleData/ThreadViewModelSampleData.xaml @@ -0,0 +1,16 @@ +<Juick_ViewModels:ThreadViewModel xmlns:Juick_ViewModels="clr-namespace:Juick.ViewModels" Caption="#333333" Mid="86" RestUri="Augue vestibulum ligula senectus dolor"> + <Juick_ViewModels:ThreadViewModel.Items> + <Juick_ViewModels:PostItem MessageText="Integer vestibulum maecenas mauris duis" + MID="51" RID="29" Status="Quisque adipiscing parturient nam vestibulum" + Username="@ugnich" /> + <Juick_ViewModels:PostItem MessageText="Lorem Ipsum - это текст-рыба, часто используемый в печати и вэб-дизайне. Lorem Ipsum является стандартной рыбой для текстов на латинице с начала XVI века. В то время некий безымянный печатник создал большую коллекцию размеров и форм шрифтов, используя Lorem Ipsum для распечатки образцов. Lorem Ipsum не только успешно пережил без заметных изменений пять веков, но и перешагнул в электронный дизайн. Его популяризации в новое время послужили публикация листов Letraset с образцами Lorem Ipsum в 60-х годах и, в более недавнее время, программы электронной вёрстки типа Aldus PageMaker, в шаблонах которых используется Lorem Ipsum." MID="21" RID="57" Status="Est donec etiam consequat convallis" Username="@ugnich"/> + <Juick_ViewModels:PostItem MessageText="Nullam ante bibendum vivamus dictumst" MID="91" RID="43" Status="Eleifend adipiscing" Username="@ugnich"/> + <Juick_ViewModels:PostItem MessageText="Parturient aliquam facilisi fermentum aliquet" MID="42" RID="12" Status="Hac leo" Username="Blandit fusce fringilla habitasse auctor"/> + <Juick_ViewModels:PostItem MessageText="Faucibus mus hendrerit arcu" MID="84" RID="29" Status="Diam nec habitant" Username="Eget himenaeos inceptos"/> + <Juick_ViewModels:PostItem MessageText="Vestibulum imperdiet malesuada congue penatibus" MID="48" RID="26" Status="Elit porttitor" Username="Lorem enim interdum"/> + <Juick_ViewModels:PostItem MessageText="Commodo conubia vestibulum erat cursus" MID="14" RID="70" Status="Cubilia lobortis tincidunt" Username="Nascetur eros dictum lectus"/> + <Juick_ViewModels:PostItem MessageText="Non pharetra tristique per" MID="80" RID="43" Status="Ultricies morbi" Username="Libero dapibus nulla"/> + <Juick_ViewModels:PostItem MessageText="Proin adipiscing nibh placerat" MID="65" RID="52" Status="Venenatis sed sem nisi" Username="Vulputate curabitur parturient egestas sit"/> + <Juick_ViewModels:PostItem MessageText="Phasellus nisl" MID="55" RID="25" Status="Vel euismod" Username="Pulvinar sagittis"/> + </Juick_ViewModels:ThreadViewModel.Items> +</Juick_ViewModels:ThreadViewModel> diff --git a/Juick/ThreadView.xaml b/Juick/ThreadView.xaml index 2778e2f..2f67219 100644 --- a/Juick/ThreadView.xaml +++ b/Juick/ThreadView.xaml @@ -1,92 +1,55 @@ -<phone:PhoneApplicationPage
- x:Class="Juick.ThreadView"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
- xmlns:phoneshell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:controls="clr-namespace:Juick.Controls" xmlns:bindings="clr-namespace:Juick.Classes"
- FontFamily="{StaticResource PhoneFontFamilyNormal}"
- FontSize="{StaticResource PhoneFontSizeNormal}"
- Foreground="{StaticResource PhoneForegroundBrush}"
- SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
- mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
- phoneshell:SystemTray.IsVisible="True">
-
- <!--LayoutRoot is the root grid where all page content is placed-->
- <Grid x:Name="LayoutRoot" Background="Transparent">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
-
- <!--TitlePanel contains the name of the application and page title-->
- <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
- <TextBlock x:Name="ApplicationTitle" Text="{Binding Caption}" Style="{StaticResource PhoneTextNormalStyle}"/>
- </StackPanel>
-
- <!--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>
- <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="0 0 0 1">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto" />
- <ColumnDefinition Width="*" />
- </Grid.ColumnDefinitions>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <RowDefinition Height="Auto" />
- <!-- RowDefinition Height="Auto" / -->
- </Grid.RowDefinitions>
- <Image bindings:LowProfileImageLoader.UriSource="{Binding AvatarUri}" 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}" />
- <!--Style="{StaticResource PhoneTextNormalStyle}"-->
- <controls:HyperLinkRichTextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
- Foreground="{StaticResource PhoneForegroundBrush}"
- Margin="5,0,5,5" VerticalAlignment="Top"
- TextWrapping="Wrap" HorizontalAlignment="Left"
- IsReadOnly="True" Text="{Binding MessageText}" />
- <Image bindings:LowProfileImageLoader.UriSource="{Binding Attachment}" Grid.Row="2" Grid.Column="0" Margin="3" Grid.ColumnSpan="2" />
- <!-- TextBlock Text="{Binding Status}" Grid.Row="3" 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>
- </Grid>
- </Grid>
-
- <phone:PhoneApplicationPage.ApplicationBar>
- <phoneshell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
- <!--<phoneshell:ApplicationBarIconButton IconUri="/Images/appbar.feature.email.rest.png" Text="New post" Click="ApplicationBarIconButtonClick1"/>
- <phoneshell:ApplicationBarIconButton IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" Click="ApplicationBarIconButtonClick" />-->
-
- <phoneshell:ApplicationBar.MenuItems>
- <phoneshell:ApplicationBarMenuItem Text="Recommend/Unrecommend" Click="RecommendBarMenuItem_Click"/>
- <phoneshell:ApplicationBarMenuItem Text="Subscribe" Click="SubscribeBarMenuItem_Click"/>
- <phoneshell:ApplicationBarMenuItem Text="Unsubscribe" Click="UnsubscribeBarMenuItem_Click"/>
- </phoneshell:ApplicationBar.MenuItems>
- </phoneshell:ApplicationBar>
- </phone:PhoneApplicationPage.ApplicationBar>
-
-</phone:PhoneApplicationPage>
+<phone:PhoneApplicationPage + x:Class="Juick.ThreadView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" + xmlns:phoneshell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:controls="clr-namespace:Juick.Controls" xmlns:bindings="clr-namespace:Juick.Classes" + FontFamily="{StaticResource PhoneFontFamilyNormal}" + FontSize="{StaticResource PhoneFontSizeNormal}" + Foreground="{StaticResource PhoneForegroundBrush}" + SupportedOrientations="PortraitOrLandscape" Orientation="Portrait" + mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480" + phoneshell:SystemTray.IsVisible="True" CacheMode="BitmapCache"> + + <!--LayoutRoot is the root grid where all page content is placed--> + <Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{d:DesignData /SampleData/ThreadViewModelSampleData.xaml}"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition/> + </Grid.RowDefinitions> + + <!--TitlePanel contains the name of the application and page title--> + <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> + <TextBlock x:Name="ApplicationTitle" Style="{StaticResource PhoneTextNormalStyle}" Text="{Binding Caption}"> </TextBlock> + </StackPanel> + + <!--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" DataContext="{Binding}" + ItemTemplate="{StaticResource PostItemDataTemplate}"> + <ListBox.ItemContainerStyle> + <Style TargetType="ListBoxItem"> + <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter> + </Style> + </ListBox.ItemContainerStyle> + </ListBox> + </Grid> + </Grid> + + <phone:PhoneApplicationPage.ApplicationBar> + <phoneshell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> + <!--<phoneshell:ApplicationBarIconButton IconUri="/Images/appbar.feature.email.rest.png" Text="New post" Click="ApplicationBarIconButtonClick1"/> + <phoneshell:ApplicationBarIconButton IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" Click="ApplicationBarIconButtonClick" />--> + + <phoneshell:ApplicationBar.MenuItems> + <phoneshell:ApplicationBarMenuItem Text="Recommend/Unrecommend" Click="RecommendBarMenuItem_Click"/> + <phoneshell:ApplicationBarMenuItem Text="Subscribe" Click="SubscribeBarMenuItem_Click"/> + <phoneshell:ApplicationBarMenuItem Text="Unsubscribe" Click="UnsubscribeBarMenuItem_Click"/> + </phoneshell:ApplicationBar.MenuItems> + </phoneshell:ApplicationBar> + </phone:PhoneApplicationPage.ApplicationBar> + +</phone:PhoneApplicationPage> diff --git a/Juick/ViewModels/AppViewModel.cs b/Juick/ViewModels/AppViewModel.cs index 4b30c08..e3a58bb 100644 --- a/Juick/ViewModels/AppViewModel.cs +++ b/Juick/ViewModels/AppViewModel.cs @@ -19,12 +19,7 @@ namespace Juick.ViewModels readonly HttpNotificationChannel pushChannel; // The name of our push channel. - private const string channelName = "JuickChannel"; - - public void UpdateNetworkStatus() - { - NetworkUnavailable = !DeviceNetworkInformation.IsNetworkAvailable; - } + string channelName = "JuickChannel"; public void UpdateNetworkStatus() { @@ -38,19 +33,24 @@ namespace Juick.ViewModels pushChannel = HttpNotificationChannel.Find(channelName); // If the channel was not found, then create a new connection to the push service. - if (_pushChannel == null) + if (pushChannel == null) { - _pushChannel = new HttpNotificationChannel(channelName); + pushChannel = new HttpNotificationChannel(channelName); // Register for all the events before attempting to open the channel. - _pushChannel.ChannelUriUpdated += (sender, e) => EnableNotifications(e.ChannelUri.ToString()); - _pushChannel.ErrorOccurred += (sender, e) => DisableNotifications(); + pushChannel.ChannelUriUpdated += (sender, e) => { + EnableNotifications(); + }; + pushChannel.ErrorOccurred += (sender, e) => + { + DisableNotifications(); + }; // Register for this notification only if you need to receive the notifications while your application is running. // Register for this notification only if you need to receive the notifications while your application is running. - _pushChannel.ShellToastNotificationReceived += (sender, e) => + pushChannel.ShellToastNotificationReceived += (sender, e) => { - var message = new StringBuilder(); + StringBuilder message = new StringBuilder(); string relativeUri = string.Empty; message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString()); @@ -71,21 +71,19 @@ namespace Juick.ViewModels } Debug.WriteLine("Received: " + message.ToString()); }; - - _pushChannel.Open(); - - // Bind this new channel for toast events. - _pushChannel.BindToShellToast(); - + pushChannel.Open(); } else { // The channel was already open, so just register for all the events. - _pushChannel.ChannelUriUpdated += (sender, e) => EnableNotifications(e.ChannelUri.ToString()); - _pushChannel.ErrorOccurred += (sender, e) => DisableNotifications(); + pushChannel.ChannelUriUpdated += (sender, e) => + { + EnableNotifications(); + }; + pushChannel.ErrorOccurred += (sender, e) => DisableNotifications(); // Register for this notification only if you need to receive the notifications while your application is running. - _pushChannel.ShellToastNotificationReceived += (sender, e) => + pushChannel.ShellToastNotificationReceived += (sender, e) => { StringBuilder message = new StringBuilder(); string relativeUri = string.Empty; @@ -107,10 +105,8 @@ namespace Juick.ViewModels } } Debug.WriteLine("Received: " + message.ToString()); - }; - - EnableNotifications(_pushChannel.ChannelUri.ToString()); - } + }; + } } private ObservableCollection<PageViewModel> _pages; public ObservableCollection<PageViewModel> Pages @@ -145,18 +141,6 @@ namespace Juick.ViewModels } } - private bool _isNetworkUnavailable; - public bool NetworkUnavailable - { - get { return _isNetworkUnavailable; } - set - { - _isNetworkUnavailable = value; - NotifyPropertyChanged(IsNetworkAvailablePropertyName); - } - } - - private AccountManager _acc; public AccountManager Account @@ -176,37 +160,23 @@ namespace Juick.ViewModels } } - public void EnableNotifications(string Url) + public void EnableNotifications() { if (!Account.IsAuthenticated) return; - Client.Authenticator = new HttpBasicAuthenticator(Account.UserName, Account.Password); - Debug.WriteLine(Url.ToString()); - if (string.IsNullOrEmpty(Account.NotificationUri) || Account.NotificationUri == Url) - { - Account.NotificationUri = Url; - RegisterNotificationUrl(Url); - } - else - { - UnregisterNotificationUrl(Account.NotificationUri); - Account.NotificationUri = Url; - RegisterNotificationUrl(Url); - } + var channelUri = pushChannel.ChannelUri.ToString(); + if (channelUri == Account.NotificationUri) + return; + Account.NotificationUri = channelUri; + if (!pushChannel.IsShellToastBound) + // Bind this new channel for toast events. + pushChannel.BindToShellToast(); } public void DisableNotifications() { - UnregisterNotificationUrl(Account.NotificationUri); + if (pushChannel.IsShellToastBound) + pushChannel.UnbindToShellToast(); Account.NotificationUri = string.Empty; - } - - void RegisterNotificationUrl(string newUrl) - { - Client.ExecuteAsync(new RestRequest("/winphone/register?url=" + newUrl), response => Debug.WriteLine(response.StatusCode)); - } - void UnregisterNotificationUrl(string oldUrl) - { - Client.ExecuteAsync(new RestRequest("/winphone/unregister?url=" + oldUrl), response => Debug.WriteLine(response.StatusCode)); - } + } } } diff --git a/Juick/ViewModels/LoginViewModel.cs b/Juick/ViewModels/LoginViewModel.cs index 95528fe..c0bf1f9 100644 --- a/Juick/ViewModels/LoginViewModel.cs +++ b/Juick/ViewModels/LoginViewModel.cs @@ -2,12 +2,11 @@ using System.Net; using System.Windows; using Juick.Classes; -using Juick.ViewModels.Validation; using RestSharp; namespace Juick.ViewModels { - public class LoginViewModel : DataViewModelBase + public class LoginViewModel : ViewModelBase { private string _username; private string _password; @@ -60,11 +59,12 @@ namespace Juick.ViewModels App.AppContext.Account.UserName = Username; App.AppContext.Account.Password = Password; App.AppContext.Account.IsAuthenticated = true; + App.AppContext.EnableNotifications(); ((App)Application.Current).NavigateTo(NextUri, true); } else { - AddError("Username", "Invalid username or password", false); + MessageBox.Show("Invalid username or password", "Error", MessageBoxButton.OK); } }); } diff --git a/Juick/ViewModels/NewPostViewModel.cs b/Juick/ViewModels/NewPostViewModel.cs new file mode 100644 index 0000000..3c28cc7 --- /dev/null +++ b/Juick/ViewModels/NewPostViewModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +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; + +namespace Juick.ViewModels +{ + public class NewPostViewModel : ViewModelBase + { + public PostItem ReplyTo { get; set; } + + public PostItem Draft { get; set; } + + public BitmapImage Attachment { get; set; } + + public NewPostViewModel(PostItem replyTo) + { + ReplyTo = replyTo; + } + } +} diff --git a/Juick/ViewModels/PostItem.cs b/Juick/ViewModels/PostItem.cs index 97935b3..88f6b86 100644 --- a/Juick/ViewModels/PostItem.cs +++ b/Juick/ViewModels/PostItem.cs @@ -1,6 +1,8 @@ using System; using System.Net; using JuickApi; +using Juick.Classes; +using System.Globalization; namespace Juick.ViewModels { @@ -11,8 +13,11 @@ namespace Juick.ViewModels MID = message.Mid; RID = message.Rid; Username = message.User.UName; - Status = string.Format("Posted on: {0}, replies: {1}", message.Timestamp, message.Replies); - + // Juick timestamp in utc: 2013-04-22 13:14:30 + var timestamp = DateTime.ParseExact(message.Timestamp, "yyyy-MM-dd HH:mm:ss", null); + Status = string.Format("{0}", DateHelper.PrettyDate(timestamp.ToLocalTime())); + if (message.Replies > 0) + Status = string.Format("{0}, replies: {1}", Status, message.Replies); MessageText = HttpUtility.HtmlDecode(message.Body); if (message.Tags != null) |