Merge branch 'develop'

This commit is contained in:
mgroves 2011-08-15 22:00:12 -04:00
commit 01e331ca6a
42 changed files with 227 additions and 78 deletions

5
.gitignore vendored
View file

@ -45,5 +45,6 @@ _ReSharper*/
# Office Temp Files # Office Temp Files
~$* ~$*
#monodroid private beta #not source
monodroid*.msi monodroid*.msi
Deploy

View file

@ -31,8 +31,8 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />

View file

@ -1,9 +1,11 @@
using Android.Content; using Android.Content;
using Android.Database.Sqlite; using Android.Database.Sqlite;
using Android.Runtime;
using Android.Util; using Android.Util;
namespace MonoStockPortfolio.Core namespace MonoStockPortfolio.Core
{ {
[Preserve(AllMembers = true)]
public abstract class AndroidSqliteBase : SQLiteOpenHelper public abstract class AndroidSqliteBase : SQLiteOpenHelper
{ {
public const string PORTFOLIO_TABLE_NAME = "Portfolios"; public const string PORTFOLIO_TABLE_NAME = "Portfolios";
@ -32,7 +34,6 @@ namespace MonoStockPortfolio.Core
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('AMZN', '500', '180.00', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('AMZN', '500', '180.00', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('AAPL', '500', '322.56', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('AAPL', '500', '322.56', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('MSFT', '500', '27.91', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('MSFT', '500', '27.91', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('NOVL', '500', '5.92', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('S', '500', '4.23', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('S', '500', '4.23', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('VZ', '500', '35.78', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('VZ', '500', '35.78', 1)");
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('T', '500', '29.38', 1)"); db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('T', '500', '29.38', 1)");

View file

@ -6,9 +6,11 @@ using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Core.Config namespace MonoStockPortfolio.Core.Config
{ {
[Preserve(AllMembers = true)]
public class AndroidSqliteConfigRepository : AndroidSqliteBase, IConfigRepository public class AndroidSqliteConfigRepository : AndroidSqliteBase, IConfigRepository
{ {
public AndroidSqliteConfigRepository(Context context) : base(context) public AndroidSqliteConfigRepository(Context context)
: base(context)
{ } { }
public IEnumerable<StockDataItem> GetStockItems() public IEnumerable<StockDataItem> GetStockItems()

View file

@ -31,8 +31,8 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />

View file

@ -8,6 +8,7 @@ using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Core.PortfolioRepositories namespace MonoStockPortfolio.Core.PortfolioRepositories
{ {
[Preserve(AllMembers = true)]
public class AndroidSqlitePortfolioRepository : AndroidSqliteBase, IPortfolioRepository public class AndroidSqlitePortfolioRepository : AndroidSqliteBase, IPortfolioRepository
{ {
public AndroidSqlitePortfolioRepository(Context context) public AndroidSqlitePortfolioRepository(Context context)
@ -78,7 +79,7 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
public Portfolio GetPortfolioByName(string portfolioName) public Portfolio GetPortfolioByName(string portfolioName)
{ {
var cursor = Db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, " Name = '" + portfolioName + "'", null, null, null, null); var cursor = Db.RawQuery("SELECT id, Name FROM " + PORTFOLIO_TABLE_NAME + " WHERE Name = ?", new[] {portfolioName} );
if (cursor.Count > 0) if (cursor.Count > 0)
{ {
cursor.MoveToNext(); cursor.MoveToNext();
@ -114,6 +115,15 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
return position; return position;
} }
public bool IsTickerAlreadyBeingTracked(string ticker, long portfolioId)
{
var cursor = Db.RawQuery("SELECT 1 FROM " + POSITION_TABLE_NAME + " WHERE Ticker = ? AND ContainingPortfolioID = ?",
new[] { ticker.ToUpper(), portfolioId.ToString() });
var result = cursor.Count > 0;
if(!cursor.IsClosed) cursor.Close();
return result;
}
public IList<Position> GetAllPositions(long portfolioId) public IList<Position> GetAllPositions(long portfolioId)
{ {
var list = new List<Position>(); var list = new List<Position>();
@ -179,7 +189,7 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
{ {
var positionValues = new ContentValues(); var positionValues = new ContentValues();
positionValues.Put("PricePerShare", (double)position.PricePerShare); positionValues.Put("PricePerShare", (double)position.PricePerShare);
positionValues.Put("Ticker", position.Ticker); positionValues.Put("Ticker", position.Ticker.ToUpper());
positionValues.Put("Shares", (double)position.Shares); positionValues.Put("Shares", (double)position.Shares);
positionValues.Put("ContainingPortfolioID", position.ContainingPortfolioID); positionValues.Put("ContainingPortfolioID", position.ContainingPortfolioID);
return positionValues; return positionValues;

View file

@ -15,5 +15,6 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
void SavePosition(Position position); void SavePosition(Position position);
void DeletePositionById(long positionId); void DeletePositionById(long positionId);
Position GetPositionById(long positionId); Position GetPositionById(long positionId);
bool IsTickerAlreadyBeingTracked(string ticker, long portfolioId);
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.Runtime;
using Android.Util; using Android.Util;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.StockData; using MonoStockPortfolio.Core.StockData;
@ -8,6 +9,7 @@ using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Core.Services namespace MonoStockPortfolio.Core.Services
{ {
[Preserve(AllMembers = true)]
public class PortfolioService : IPortfolioService public class PortfolioService : IPortfolioService
{ {
private readonly IPortfolioRepository _portRepo; private readonly IPortfolioRepository _portRepo;
@ -33,7 +35,7 @@ namespace MonoStockPortfolio.Core.Services
var positions = _portRepo.GetAllPositions(portfolioID); var positions = _portRepo.GetAllPositions(portfolioID);
if (!positions.Any()) return new List<PositionResultsViewModel>(); if (!positions.Any()) return new List<PositionResultsViewModel>();
var tickers = positions.Select(p => p.Ticker); var tickers = positions.Select(p => p.Ticker).Distinct();
var stockData = _stockRepo.GetStockQuotes(tickers); var stockData = _stockRepo.GetStockQuotes(tickers);
foreach (var position in positions) foreach (var position in positions)

View file

@ -3,12 +3,14 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using Android.Runtime;
using Android.Util; using Android.Util;
using LumenWorks.Framework.IO.Csv; using LumenWorks.Framework.IO.Csv;
using MonoStockPortfolio.Entities; using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Core.StockData namespace MonoStockPortfolio.Core.StockData
{ {
[Preserve(AllMembers = true)]
public class YahooStockDataProvider : IStockDataProvider public class YahooStockDataProvider : IStockDataProvider
{ {
private const string LAST_TRADE_PRICE_ONLY = "l1"; private const string LAST_TRADE_PRICE_ONLY = "l1";
@ -91,11 +93,9 @@ namespace MonoStockPortfolio.Core.StockData
var d = new YahooFinanceStockData(); var d = new YahooFinanceStockData();
d.Ticker = csvReader[0]; d.Ticker = csvReader[0];
decimal.TryParse(csvReader[1], out d.LastTradePrice); decimal.TryParse(csvReader[1], out d.LastTradePrice);
//d.LastTradePrice = decimal.Parse(csvReader[1]);
d.Name = csvReader[2]; d.Name = csvReader[2];
d.Volume = csvReader[3]; d.Volume = csvReader[3];
decimal.TryParse(csvReader[4], out d.Change); decimal.TryParse(csvReader[4], out d.Change);
//d.Change = decimal.Parse(csvReader[4]);
d.LastTradeTime = csvReader[5]; d.LastTradeTime = csvReader[5];
d.RealTimeLastTradeWithTime = csvReader[6]; d.RealTimeLastTradeWithTime = csvReader[6];
d.ChangeRealTime = csvReader[7]; d.ChangeRealTime = csvReader[7];

View file

@ -29,6 +29,8 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

View file

@ -30,6 +30,8 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Machine.Specifications"> <Reference Include="Machine.Specifications">
@ -65,6 +67,7 @@
<Compile Include="Presenters\EditPortfolio\EditPortfolioTests.cs" /> <Compile Include="Presenters\EditPortfolio\EditPortfolioTests.cs" />
<Compile Include="Presenters\EditPosition\EditPositionTests.cs" /> <Compile Include="Presenters\EditPosition\EditPositionTests.cs" />
<Compile Include="Presenters\Main\MainPresenterTests.cs" /> <Compile Include="Presenters\Main\MainPresenterTests.cs" />
<Compile Include="Presenters\Main\When_the_user_wants_to_see_About_info.cs" />
<Compile Include="Presenters\Portfolio\PortfolioPresenterTests.cs" /> <Compile Include="Presenters\Portfolio\PortfolioPresenterTests.cs" />
<Compile Include="Presenters\Portfolio\When_done_initializing_a_Portfolio_Presenter.cs" /> <Compile Include="Presenters\Portfolio\When_done_initializing_a_Portfolio_Presenter.cs" />
<Compile Include="Presenters\Config\When_initialize_the_config_presenter.cs" /> <Compile Include="Presenters\Config\When_initialize_the_config_presenter.cs" />

View file

@ -1,3 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Machine.Specifications; using Machine.Specifications;
using MonoStockPortfolio.Activites.EditPositionScreen; using MonoStockPortfolio.Activites.EditPositionScreen;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
@ -22,5 +25,9 @@ namespace MonoStockPortfolio.Tests.Presenters.EditPosition
_presenter = new EditPositionPresenter(_mockPortfolioRepository, _mockStockService); _presenter = new EditPositionPresenter(_mockPortfolioRepository, _mockStockService);
}; };
protected static void MockPositionMatches(Expression<Predicate<IList<string>>> match)
{
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.Matches(match)), Occurs.Exactly(1));
}
} }
} }

View file

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using Machine.Specifications; using Machine.Specifications;
using MonoStockPortfolio.Activites.EditPositionScreen; using MonoStockPortfolio.Activites.EditPositionScreen;
using MonoStockPortfolio.Entities; using MonoStockPortfolio.Entities;
@ -37,10 +36,5 @@ namespace MonoStockPortfolio.Tests.Presenters.EditPosition
MockPositionMatches(x => x.Any(p => p == "Please enter a valid, positive price per share")); MockPositionMatches(x => x.Any(p => p == "Please enter a valid, positive price per share"));
It should_not_tell_the_view_to_go_back_to_the_main_activity = () => It should_not_tell_the_view_to_go_back_to_the_main_activity = () =>
Mock.Assert(() => _mockView.GoBackToPortfolioActivity(), Occurs.Never()); Mock.Assert(() => _mockView.GoBackToPortfolioActivity(), Occurs.Never());
private static void MockPositionMatches(Expression<Predicate<IList<string>>> match)
{
Mock.Assert(() => _mockView.ShowErrorMessages(Arg.Matches(match)), Occurs.Exactly(1));
}
} }
} }

View file

@ -1,13 +1,13 @@
using Machine.Specifications; using Machine.Specifications;
using Telerik.JustMock; using Telerik.JustMock;
namespace MonoStockPortfolio.Tests.Presenters namespace MonoStockPortfolio.Tests.Presenters.Main
{ {
[Tags("UnitTest")] [Tags("UnitTest")]
public class When_the_user_wants_to_exit_the_app : Given_an_initialized_Main_Presenter public class When_the_user_wants_to_exit_the_app : Given_an_initialized_Main_Presenter
{ {
Because of = () => Because of = () =>
_presenter.ExitApplication(); _presenter.ExitApplication();
It should_tell_the_view_to_start_up_the_config_activity = () => It should_tell_the_view_to_start_up_the_config_activity = () =>
Mock.Assert(() => _mockView.ExitApplication(), Occurs.Exactly(1)); Mock.Assert(() => _mockView.ExitApplication(), Occurs.Exactly(1));

View file

@ -0,0 +1,33 @@
using Machine.Specifications;
using Telerik.JustMock;
namespace MonoStockPortfolio.Tests.Presenters.Main
{
[Tags("UnitTest")]
public class When_the_user_wants_to_see_About_info : Given_an_initialized_Main_Presenter
{
static string _expectedMessage;
Establish context = () =>
{
_expectedMessage = "Matthew D. Groves © 2011\n" +
"Source code:\n" +
"\n" +
"http://tinyurl.com/mspSource\n" +
"\n" +
"Contact me:\n" +
"\n" +
"http://mgroves.com\n" +
"http://twitter.com/mgroves\n" +
"webmaster@mgroves.com";
};
Because of = () =>
_presenter.GotoAboutInfo();
It should_tell_the_view_toshow_the_about_info = () =>
Mock.Assert(() => _mockView.ShowAboutInfo(Arg.AnyString), Occurs.Exactly(1));
It should_pass_the_expected_message_to_the_about_info = () =>
Mock.Assert(() => _mockView.ShowAboutInfo(_expectedMessage), Occurs.Exactly(1));
}
}

View file

@ -20,7 +20,7 @@ namespace MonoStockPortfolio.Tests.Services
Because of = () => Because of = () =>
{ {
_quotes = _svc.GetStockQuotes(new[] { "GOOG", "AMZN", "AAPL", "MSFT", "NOVL", "S", "VZ", "T" }) _quotes = _svc.GetStockQuotes(new[] { "GOOG", "AMZN", "AAPL", "MSFT", "S", "VZ", "T" })
.ToList(); .ToList();
}; };

View file

@ -26,10 +26,12 @@ Global
{E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Release|Any CPU.Build.0 = Release|Any CPU {E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Release|Any CPU.Build.0 = Release|Any CPU
{E23D8575-CE4E-4716-B9C7-70115D23ADBB}.Release|Any CPU.Deploy.0 = Release|Any CPU
{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Debug|Any CPU.Build.0 = Debug|Any CPU {251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Release|Any CPU.ActiveCfg = Release|Any CPU {251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Release|Any CPU.Build.0 = Release|Any CPU {251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Release|Any CPU.Build.0 = Release|Any CPU
{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}.Release|Any CPU.Deploy.0 = Release|Any CPU
{05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Debug|Any CPU.Build.0 = Debug|Any CPU {05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Release|Any CPU.ActiveCfg = Release|Any CPU {05A57650-3B41-46FF-9EAD-9112B5EFBEED}.Release|Any CPU.ActiveCfg = Release|Any CPU

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.App; using Android.App;
@ -14,7 +15,6 @@ namespace MonoStockPortfolio.Activites.ConfigScreen
public class ConfigActivity : Activity, IConfigView public class ConfigActivity : Activity, IConfigView
{ {
[LazyView(Resource.Id.configList)] private ListView ConfigList; [LazyView(Resource.Id.configList)] private ListView ConfigList;
[LazyView(Resource.Id.btnSaveConfig)] private Button SaveConfigButton;
[IoC] IConfigPresenter _presenter; [IoC] IConfigPresenter _presenter;
@ -36,9 +36,27 @@ namespace MonoStockPortfolio.Activites.ConfigScreen
WireUpEvents(); WireUpEvents();
} }
void WireUpEvents() private void WireUpEvents()
{ {
SaveConfigButton.Click += SaveConfigButton_Click; ConfigList.ItemClick += ConfigList_ItemClick;
}
void ConfigList_ItemClick(object sender, ItemEventArgs e)
{
SaveConfiguration();
}
void SaveConfiguration()
{
var checkedItems = new List<StockDataItem>();
for(int i =0;i<ConfigList.Count;i++)
{
if (ConfigList.IsItemChecked(i))
{
checkedItems.Add((StockDataItem) i);
}
}
_presenter.SaveConfig(checkedItems);
} }
#region IConfigView members #region IConfigView members
@ -65,18 +83,5 @@ namespace MonoStockPortfolio.Activites.ConfigScreen
} }
#endregion #endregion
void SaveConfigButton_Click(object sender, System.EventArgs e)
{
var checkedItems = new List<StockDataItem>();
for(int i =0;i<ConfigList.Count;i++)
{
if (ConfigList.IsItemChecked(i))
{
checkedItems.Add((StockDataItem) i);
}
}
_presenter.SaveConfig(checkedItems);
}
} }
} }

View file

@ -1,11 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.Runtime;
using MonoStockPortfolio.Core.Config; using MonoStockPortfolio.Core.Config;
using MonoStockPortfolio.Entities; using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Core; using MonoStockPortfolio.Core;
namespace MonoStockPortfolio.Activites.ConfigScreen namespace MonoStockPortfolio.Activites.ConfigScreen
{ {
[Preserve(AllMembers = true)]
public class ConfigPresenter : IConfigPresenter public class ConfigPresenter : IConfigPresenter
{ {
private IConfigView _currentView; private IConfigView _currentView;

View file

@ -1,11 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.Runtime;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Entities; using MonoStockPortfolio.Entities;
using MonoStockPortfolio.Framework; using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites.EditPortfolioScreen namespace MonoStockPortfolio.Activites.EditPortfolioScreen
{ {
[Preserve(AllMembers = true)]
public class EditPortfolioPresenter : IEditPortfolioPresenter public class EditPortfolioPresenter : IEditPortfolioPresenter
{ {
private IEditPortfolioView _currentView; private IEditPortfolioView _currentView;

View file

@ -1,4 +1,6 @@
using System;
using System.Linq; using System.Linq;
using Android.Runtime;
using Android.Util; using Android.Util;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.StockData; using MonoStockPortfolio.Core.StockData;
@ -7,6 +9,7 @@ using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites.EditPositionScreen namespace MonoStockPortfolio.Activites.EditPositionScreen
{ {
[Preserve(AllMembers = true)]
public class EditPositionPresenter : IEditPositionPresenter public class EditPositionPresenter : IEditPositionPresenter
{ {
private IEditPositionView _currentView; private IEditPositionView _currentView;
@ -80,11 +83,18 @@ namespace MonoStockPortfolio.Activites.EditPositionScreen
private string ValidateTicker(string ticker) private string ValidateTicker(string ticker)
{ {
if (_stockService.IsValidTicker(ticker)) try
{ {
return string.Empty; if (_stockService.IsValidTicker(ticker))
{
return string.Empty;
}
return "Invalid Ticker Name";
} }
return "Invalid Ticker Name"; catch (Exception ex)
} {
return "Unable to load stock information from the web";
}
}
} }
} }

View file

@ -10,5 +10,6 @@
void EditPortfolio(int itemId); void EditPortfolio(int itemId);
void GotoConfig(); void GotoConfig();
void ExitApplication(); void ExitApplication();
void GotoAboutInfo();
} }
} }

View file

@ -11,5 +11,6 @@ namespace MonoStockPortfolio.Activites.MainScreen
void StartEditPortfolioActivity(int itemId); void StartEditPortfolioActivity(int itemId);
void StartConfigActivity(); void StartConfigActivity();
void ExitApplication(); void ExitApplication();
void ShowAboutInfo(string message);
} }
} }

View file

@ -4,6 +4,9 @@ using System.Linq;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.OS; using Android.OS;
using Android.Text;
using Android.Text.Method;
using Android.Text.Util;
using Android.Views; using Android.Views;
using Android.Widget; using Android.Widget;
using MonoStockPortfolio.Activites.ConfigScreen; using MonoStockPortfolio.Activites.ConfigScreen;
@ -47,6 +50,22 @@ namespace MonoStockPortfolio.Activites.MainScreen
Finish(); Finish();
} }
public void ShowAboutInfo(string message)
{
var spannable = new SpannableString(message);
Linkify.AddLinks(spannable, MatchOptions.All);
var alertBox = new AlertDialog.Builder(this)
.SetNeutralButton("Ok", (x, y) => { })
.SetMessage(spannable)
.SetTitle("About Mono Stock Portfolio")
.Create();
alertBox.Show();
((TextView)alertBox.FindViewById(Android.Resource.Id.Message)).MovementMethod = LinkMovementMethod.Instance;
}
public void StartEditPortfolioActivity(int itemId) public void StartEditPortfolioActivity(int itemId)
{ {
var intent = EditPortfolioActivity.EditIntent(this, itemId); var intent = EditPortfolioActivity.EditIntent(this, itemId);
@ -114,6 +133,8 @@ namespace MonoStockPortfolio.Activites.MainScreen
{ {
var configItem = menu.Add(0, 1, 1, "Config".ToJ()); var configItem = menu.Add(0, 1, 1, "Config".ToJ());
configItem.SetIcon(Resource.Drawable.ic_menu_preferences); configItem.SetIcon(Resource.Drawable.ic_menu_preferences);
var aboutItem = menu.Add(0, 1, 1, "About".ToJ());
aboutItem.SetIcon(Resource.Drawable.ic_menu_info_details); // IcMenuInfoDetails);
var exitItem = menu.Add(0, 1, 1, "Exit".ToJ()); var exitItem = menu.Add(0, 1, 1, "Exit".ToJ());
exitItem.SetIcon(Resource.Drawable.ic_menu_close_clear_cancel); exitItem.SetIcon(Resource.Drawable.ic_menu_close_clear_cancel);
return true; return true;
@ -129,6 +150,9 @@ namespace MonoStockPortfolio.Activites.MainScreen
case "Exit": case "Exit":
_presenter.ExitApplication(); _presenter.ExitApplication();
return true; return true;
case "About":
_presenter.GotoAboutInfo();
return true;
default: default:
return base.OnOptionsItemSelected(item); return base.OnOptionsItemSelected(item);
} }

View file

@ -1,9 +1,12 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Android.Runtime;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Entities; using MonoStockPortfolio.Entities;
namespace MonoStockPortfolio.Activites.MainScreen namespace MonoStockPortfolio.Activites.MainScreen
{ {
[Preserve(AllMembers = true)]
public class MainPresenter : IMainPresenter public class MainPresenter : IMainPresenter
{ {
private IPortfolioRepository _repo; private IPortfolioRepository _repo;
@ -65,5 +68,21 @@ namespace MonoStockPortfolio.Activites.MainScreen
{ {
_currentView.ExitApplication(); _currentView.ExitApplication();
} }
public void GotoAboutInfo()
{
var message = "Matthew D. Groves © 2011\n" +
"Source code:\n" +
"\n" +
"http://tinyurl.com/mspSource\n" +
"\n" +
"Contact me:\n" +
"\n" +
"http://mgroves.com\n" +
"http://twitter.com/mgroves\n" +
"webmaster@mgroves.com";
_currentView.ShowAboutInfo(message);
}
} }
} }

View file

@ -13,5 +13,6 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
void UpdateHeader(IEnumerable<StockDataItem> configItems); void UpdateHeader(IEnumerable<StockDataItem> configItems);
void ShowProgressDialog(string loadingMessage); void ShowProgressDialog(string loadingMessage);
void HideProgressDialog(); void HideProgressDialog();
void FlashMessage(string toastMessage);
} }
} }

View file

@ -83,6 +83,7 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
{ {
var textItem = new TextView(this); var textItem = new TextView(this);
textItem.Text = stockDataItem.GetStringValue(); textItem.Text = stockDataItem.GetStringValue();
textItem.TextSize = 16.55F;
textItem.SetWidth(cellwidth); textItem.SetWidth(cellwidth);
textItem.SetTextColor(Resources.GetColor(Android.Resource.Color.Black)); textItem.SetTextColor(Resources.GetColor(Android.Resource.Color.Black));
QuoteListviewHeader.AddView(textItem); QuoteListviewHeader.AddView(textItem);
@ -110,6 +111,12 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
} }
} }
[OnGuiThread]
public void FlashMessage(string toastMessage)
{
this.LongToast(toastMessage);
}
#endregion #endregion
private void WireUpEvents() private void WireUpEvents()
@ -144,7 +151,10 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
base.OnCreateContextMenu(menu, v, menuInfo); base.OnCreateContextMenu(menu, v, menuInfo);
var info = (AdapterView.AdapterContextMenuInfo)menuInfo; var info = (AdapterView.AdapterContextMenuInfo)menuInfo;
var selectedPositionId = int.Parse(info.TargetView.Tag.ToString()); var tag = info.TargetView.Tag;
if (tag == null) return;
var selectedPositionId = int.Parse(tag.ToString());
menu.SetHeaderTitle("Options".ToJ()); menu.SetHeaderTitle("Options".ToJ());
foreach (var contextItem in _presenter.GetContextItems()) foreach (var contextItem in _presenter.GetContextItems())

View file

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Android.Runtime;
using MonoStockPortfolio.Core.Config; using MonoStockPortfolio.Core.Config;
using MonoStockPortfolio.Core.PortfolioRepositories; using MonoStockPortfolio.Core.PortfolioRepositories;
using MonoStockPortfolio.Core.Services; using MonoStockPortfolio.Core.Services;
@ -8,6 +10,7 @@ using MonoStockPortfolio.Framework;
namespace MonoStockPortfolio.Activites.PortfolioScreen namespace MonoStockPortfolio.Activites.PortfolioScreen
{ {
[Preserve(AllMembers = true)]
public class PortfolioPresenter : IPortfolioPresenter public class PortfolioPresenter : IPortfolioPresenter
{ {
private IPortfolioView _currentView; private IPortfolioView _currentView;
@ -103,7 +106,16 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
{ {
_currentView.ShowProgressDialog("Loading...Please wait..."); _currentView.ShowProgressDialog("Loading...Please wait...");
_positions = GetPositions(); try
{
_positions = GetPositions();
}
catch (Exception)
{
_currentView.FlashMessage("Unable to load stock data from the web");
_positions = new List<PositionResultsViewModel>();
}
if (_positions.Any()) if (_positions.Any())
{ {
_currentView.RefreshList(_positions, GetConfigItems()); _currentView.RefreshList(_positions, GetConfigItems());

View file

@ -50,6 +50,7 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
{ {
var cell = new TextView(_context); var cell = new TextView(_context);
cell.Text = item.Items[stockDataItem]; cell.Text = item.Items[stockDataItem];
cell.TextSize = 16.55F;
cell.SetWidth(columnWidth); cell.SetWidth(columnWidth);
RedGreenHighlighting(cell, item.Items); RedGreenHighlighting(cell, item.Items);
row.Tag = item.PositionId; row.Tag = item.PositionId;
@ -62,7 +63,7 @@ namespace MonoStockPortfolio.Activites.PortfolioScreen
{ {
if (items.ContainsKey(StockDataItem.GainLoss)) if (items.ContainsKey(StockDataItem.GainLoss))
{ {
cell.SetTextColor(decimal.Parse(items[StockDataItem.GainLoss]) < 0 ? Color.Red : Color.Green); cell.SetTextColor(decimal.Parse(items[StockDataItem.GainLoss]) < 0 ? Color.Red : Color.LightGreen);
} }
} }
} }

View file

@ -19,6 +19,7 @@
<AndroidApplication>true</AndroidApplication> <AndroidApplication>true</AndroidApplication>
<AndroidStoreUncompressedFileExtensions /> <AndroidStoreUncompressedFileExtensions />
<TargetFrameworkVersion>v2.1</TargetFrameworkVersion> <TargetFrameworkVersion>v2.1</TargetFrameworkVersion>
<MandroidI18n />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -38,8 +39,8 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />
@ -95,12 +96,12 @@
<ItemGroup> <ItemGroup>
<None Include="PostSharp.Custom.targets" /> <None Include="PostSharp.Custom.targets" />
<None Include="Resources\AboutResources.txt" /> <None Include="Resources\AboutResources.txt" />
<AndroidResource Include="Resources\layout\config.xml"> <AndroidResource Include="Resources\layout\config.axml">
<SubType>AndroidResource</SubType> <SubType>AndroidResource</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\layout\main.xml"> <AndroidResource Include="Resources\layout\main.axml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
@ -108,12 +109,12 @@
<AndroidResource Include="Resources\values\strings.xml" /> <AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\layout\addportfolio.xml"> <AndroidResource Include="Resources\layout\addportfolio.axml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\layout\portfolio.xml"> <AndroidResource Include="Resources\layout\portfolio.axml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
@ -128,7 +129,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\layout\addposition.xml"> <AndroidResource Include="Resources\layout\addposition.axml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
@ -140,6 +141,9 @@
<AndroidResource Include="Resources\drawable-hdpi\ic_menu_close_clear_cancel.png" /> <AndroidResource Include="Resources\drawable-hdpi\ic_menu_close_clear_cancel.png" />
<AndroidResource Include="Resources\drawable-ldpi\ic_menu_close_clear_cancel.png" /> <AndroidResource Include="Resources\drawable-ldpi\ic_menu_close_clear_cancel.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_menu_close_clear_cancel.png" /> <AndroidResource Include="Resources\drawable-mdpi\ic_menu_close_clear_cancel.png" />
<AndroidResource Include="Resources\drawable-hdpi\ic_menu_info_details.png" />
<AndroidResource Include="Resources\drawable-ldpi\ic_menu_info_details.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_menu_info_details.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\ic_menu_refresh.png" /> <AndroidResource Include="Resources\drawable-hdpi\ic_menu_refresh.png" />

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.monostockportfolio" android:versionCode="1" android:versionName="1.0"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.monostockportfolio" android:versionCode="2" android:versionName="1.0.1">
<application android:label="MonoStockPortfolio"> <application android:label="Stock Portfolio" android:icon="@drawable/icon">
</application> </application>
<uses-sdk android:minSdkVersion="7" /> <uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />

View file

@ -32,5 +32,4 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:2.0.50727.4952 // Runtime Version:4.0.30319.237
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@ -30,13 +30,16 @@ namespace MonoStockPortfolio
public const int ic_menu_close_clear_cancel = 2130837504; public const int ic_menu_close_clear_cancel = 2130837504;
// aapt resource value: 0x7f020001 // aapt resource value: 0x7f020001
public const int ic_menu_preferences = 2130837505; public const int ic_menu_info_details = 2130837505;
// aapt resource value: 0x7f020002 // aapt resource value: 0x7f020002
public const int ic_menu_refresh = 2130837506; public const int ic_menu_preferences = 2130837506;
// aapt resource value: 0x7f020003 // aapt resource value: 0x7f020003
public const int icon = 2130837507; public const int ic_menu_refresh = 2130837507;
// aapt resource value: 0x7f020004
public const int icon = 2130837508;
private Drawable() private Drawable()
{ {
@ -58,32 +61,29 @@ namespace MonoStockPortfolio
// aapt resource value: 0x7f050002 // aapt resource value: 0x7f050002
public const int addPositionTicker = 2131034114; public const int addPositionTicker = 2131034114;
// aapt resource value: 0x7f050008 // aapt resource value: 0x7f050007
public const int btnAddPortfolio = 2131034120; public const int btnAddPortfolio = 2131034119;
// aapt resource value: 0x7f05000a // aapt resource value: 0x7f050009
public const int btnAddPosition = 2131034122; public const int btnAddPosition = 2131034121;
// aapt resource value: 0x7f050001 // aapt resource value: 0x7f050001
public const int btnSave = 2131034113; public const int btnSave = 2131034113;
// aapt resource value: 0x7f050006 // aapt resource value: 0x7f050006
public const int btnSaveConfig = 2131034118; public const int configList = 2131034118;
// aapt resource value: 0x7f050007 // aapt resource value: 0x7f050008
public const int configList = 2131034119; public const int portfolioList = 2131034120;
// aapt resource value: 0x7f050009
public const int portfolioList = 2131034121;
// aapt resource value: 0x7f050000 // aapt resource value: 0x7f050000
public const int portfolioName = 2131034112; public const int portfolioName = 2131034112;
// aapt resource value: 0x7f05000b // aapt resource value: 0x7f05000a
public const int quoteHeaderLayout = 2131034123; public const int quoteHeaderLayout = 2131034122;
// aapt resource value: 0x7f05000c // aapt resource value: 0x7f05000b
public const int quoteListview = 2131034124; public const int quoteListview = 2131034123;
private Id() private Id()
{ {

Binary file not shown.

After

(image error) Size: 2.5 KiB

Binary file not shown.

After

(image error) Size: 1.5 KiB

Binary file not shown.

After

(image error) Size: 1.8 KiB

View file

@ -12,6 +12,7 @@
android:text="Ticker" /> android:text="Ticker" />
<EditText android:id="@+id/addPositionTicker" <EditText android:id="@+id/addPositionTicker"
android:inputType="textCapCharacters"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
@ -20,6 +21,7 @@
android:text="# of shares" /> android:text="# of shares" />
<EditText android:id="@+id/addPositionShares" <EditText android:id="@+id/addPositionShares"
android:inputType="numberDecimal"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
@ -28,6 +30,7 @@
android:text="Price per share" /> android:text="Price per share" />
<EditText android:id="@+id/addPositionPrice" <EditText android:id="@+id/addPositionPrice"
android:inputType="numberDecimal"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />

View file

@ -4,9 +4,6 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent"> android:layout_height="fill_parent">
<Button android:text="Save" android:layout_height="wrap_content"
android:layout_width="fill_parent" android:id="@+id/btnSaveConfig" />
<ListView android:id="@+id/configList" <ListView android:id="@+id/configList"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />

Binary file not shown.