mirror of
https://github.com/mgroves/MonodroidStockPortfolio.git
synced 2024-12-28 03:00:17 +00:00
Merge branch 'config' into develop
This commit is contained in:
commit
3f1189254a
37 changed files with 902 additions and 3186 deletions
46
MonoStockPortfolio.Core/AndroidSqliteBase.cs
Normal file
46
MonoStockPortfolio.Core/AndroidSqliteBase.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using Android.Content;
|
||||
using Android.Database.Sqlite;
|
||||
using Android.Util;
|
||||
|
||||
namespace MonoStockPortfolio.Core
|
||||
{
|
||||
public abstract class AndroidSqliteBase : SQLiteOpenHelper
|
||||
{
|
||||
public const string PORTFOLIO_TABLE_NAME = "Portfolios";
|
||||
public const string POSITION_TABLE_NAME = "Positions";
|
||||
public const string CONFIG_TABLE_NAME = "Config";
|
||||
|
||||
public const string DATABASE_NAME = "stockportfolio.db";
|
||||
public const int DATABASE_VERSION = 1;
|
||||
|
||||
protected AndroidSqliteBase(Context context)
|
||||
: base(context, DATABASE_NAME, null, DATABASE_VERSION)
|
||||
{
|
||||
}
|
||||
|
||||
protected SQLiteDatabase Db { get { return WritableDatabase; } }
|
||||
|
||||
public override void OnCreate(SQLiteDatabase db)
|
||||
{
|
||||
db.ExecSQL("CREATE TABLE " + PORTFOLIO_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT)");
|
||||
db.ExecSQL("CREATE TABLE " + POSITION_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, Ticker TEXT, Shares REAL, PricePerShare REAL, ContainingPortfolioID INT)");
|
||||
db.ExecSQL("CREATE TABLE " + CONFIG_TABLE_NAME + " (StockItems TEXT)");
|
||||
|
||||
db.ExecSQL("INSERT INTO " + CONFIG_TABLE_NAME + " (StockItems) VALUES ('2,0,1,3')");
|
||||
db.ExecSQL("INSERT INTO " + PORTFOLIO_TABLE_NAME + " (Name) VALUES ('Sample portfolio')");
|
||||
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('GOOG', '500', '593.97', 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 ('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 ('VZ', '500', '35.78', 1)");
|
||||
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('T', '500', '29.38', 1)");
|
||||
}
|
||||
|
||||
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
||||
{
|
||||
Log.Warn("Upgrade", "Nothing to upgrade");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.Content;
|
||||
using MonoStockPortfolio.Entities;
|
||||
|
||||
namespace MonoStockPortfolio.Core.Config
|
||||
{
|
||||
public class AndroidSqliteConfigRepository : IConfigRepository
|
||||
public class AndroidSqliteConfigRepository : AndroidSqliteBase, IConfigRepository
|
||||
{
|
||||
public AndroidSqliteConfigRepository(Context context) : base(context)
|
||||
{ }
|
||||
|
||||
public IEnumerable<StockDataItem> GetStockItems()
|
||||
{
|
||||
var cursor = Db.Query(CONFIG_TABLE_NAME, new[] { "StockItems" }, null, null, null, null, null);
|
||||
string stockItemsCsv = null;
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
cursor.MoveToNext();
|
||||
stockItemsCsv = cursor.GetString(0);
|
||||
if (!cursor.IsClosed) cursor.Close();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(stockItemsCsv))
|
||||
{
|
||||
return DefaultItems();
|
||||
}
|
||||
|
||||
return stockItemsCsv.Split(',').Select(i => (StockDataItem)int.Parse(i));
|
||||
}
|
||||
|
||||
public void UpdateStockItems(List<StockDataItem> stockDataItems)
|
||||
{
|
||||
var stockItemsCsv = string.Join(",", stockDataItems.Select(i => ((int) i).ToString()).ToArray());
|
||||
var contentValues = new ContentValues();
|
||||
contentValues.Put("StockItems", stockItemsCsv);
|
||||
Db.Update(CONFIG_TABLE_NAME, contentValues, null, null);
|
||||
}
|
||||
|
||||
// this should never be called, but it's here anyway in case of some catastrophe
|
||||
private static IEnumerable<StockDataItem> DefaultItems()
|
||||
{
|
||||
var items = new List<StockDataItem>();
|
||||
items.Add(StockDataItem.Ticker);
|
||||
|
|
|
@ -6,5 +6,6 @@ namespace MonoStockPortfolio.Core.Config
|
|||
public interface IConfigRepository
|
||||
{
|
||||
IEnumerable<StockDataItem> GetStockItems();
|
||||
void UpdateStockItems(List<StockDataItem> stockDataItems);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MonoStockPortfolio.Entities;
|
||||
|
||||
namespace MonoStockPortfolio.Core
|
||||
|
@ -21,5 +24,16 @@ namespace MonoStockPortfolio.Core
|
|||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetValues<T>(this Enum value)
|
||||
{
|
||||
var enumerations = new List<Enum>();
|
||||
var fields = value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
|
||||
foreach (var fieldInfo in fields)
|
||||
{
|
||||
enumerations.Add((Enum)fieldInfo.GetValue(value));
|
||||
}
|
||||
return enumerations.Cast<T>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,11 +31,7 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FileHelpers">
|
||||
<HintPath>..\libs\FileHelpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
@ -46,14 +42,15 @@
|
|||
<Compile Include="Config\IConfigRepository.cs" />
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="EnumExtensions.cs" />
|
||||
<Compile Include="AndroidSqliteBase.cs" />
|
||||
<Compile Include="PortfolioRepositories\AndroidSqlitePortfolioRepository.cs" />
|
||||
<Compile Include="PortfolioRepositories\IPortfolioRepository.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\IPortfolioService.cs" />
|
||||
<Compile Include="Services\PortfolioService.cs" />
|
||||
<Compile Include="StockData\CsvParser.cs" />
|
||||
<Compile Include="StockData\GoogleStockDataProvider.cs" />
|
||||
<Compile Include="StockData\IStockDataProvider.cs" />
|
||||
<Compile Include="StockData\YahooFinanceStockData.cs" />
|
||||
<Compile Include="StockData\YahooStockDataProvider.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MonoStockPortfolio.Entities\MonoStockPortfolio.Entities.csproj">
|
||||
|
|
|
@ -7,41 +7,32 @@ using MonoStockPortfolio.Entities;
|
|||
|
||||
namespace MonoStockPortfolio.Core.PortfolioRepositories
|
||||
{
|
||||
public class AndroidSqlitePortfolioRepository : IPortfolioRepository
|
||||
public class AndroidSqlitePortfolioRepository : AndroidSqliteBase, IPortfolioRepository
|
||||
{
|
||||
private OpenHelper _dbHelper;
|
||||
private SQLiteDatabase _db;
|
||||
private const string PORTFOLIO_TABLE_NAME = "Portfolios";
|
||||
private const string DATABASE_NAME = "stockportfolio.db";
|
||||
private const int DATABASE_VERSION = 1;
|
||||
private const string POSITION_TABLE_NAME = "Positions";
|
||||
|
||||
public AndroidSqlitePortfolioRepository(Context context)
|
||||
{
|
||||
_dbHelper = new OpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
_db = _dbHelper.WritableDatabase;
|
||||
}
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public IList<Portfolio> GetAllPortfolios()
|
||||
{
|
||||
var list = new List<Portfolio>();
|
||||
var cursor = _db.Query(PORTFOLIO_TABLE_NAME, new[] {"id", "Name"}, null, null, null, null, null);
|
||||
if(cursor.Count > 0)
|
||||
var cursor = Db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, null, null, null, null, null);
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
while(cursor.MoveToNext())
|
||||
while (cursor.MoveToNext())
|
||||
{
|
||||
var portfolio = new Portfolio(cursor.GetInt(0));
|
||||
portfolio.Name = cursor.GetString(1);
|
||||
list.Add(portfolio);
|
||||
}
|
||||
}
|
||||
if(!cursor.IsClosed) cursor.Close();
|
||||
if (!cursor.IsClosed) cursor.Close();
|
||||
return list;
|
||||
}
|
||||
|
||||
public Portfolio GetPortfolioById(long portfolioId)
|
||||
{
|
||||
var cursor = _db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, " ID = " + portfolioId, null, null, null, null);
|
||||
var cursor = Db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, " ID = " + portfolioId, null, null, null, null);
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
cursor.MoveToNext();
|
||||
|
@ -67,26 +58,26 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
|
|||
|
||||
public void DeletePortfolioById(int portfolioId)
|
||||
{
|
||||
_db.BeginTransaction();
|
||||
Db.BeginTransaction();
|
||||
try
|
||||
{
|
||||
_db.Delete(PORTFOLIO_TABLE_NAME, "id = " + portfolioId, null);
|
||||
_db.Delete(POSITION_TABLE_NAME, "ContainingPortfolioID = " + portfolioId, null);
|
||||
_db.SetTransactionSuccessful();
|
||||
Db.Delete(PORTFOLIO_TABLE_NAME, "id = " + portfolioId, null);
|
||||
Db.Delete(POSITION_TABLE_NAME, "ContainingPortfolioID = " + portfolioId, null);
|
||||
Db.SetTransactionSuccessful();
|
||||
}
|
||||
catch (SQLiteException)
|
||||
{
|
||||
Log.E("DeletePortfolio", "SQLiteException => Id = " + portfolioId);
|
||||
Log.Error("DeletePortfolio", "SQLiteException => Id = " + portfolioId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_db.EndTransaction();
|
||||
Db.EndTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public Portfolio GetPortfolioByName(string portfolioName)
|
||||
{
|
||||
var cursor = _db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, " Name = '" + portfolioName + "'", null, null, null, null);
|
||||
var cursor = Db.Query(PORTFOLIO_TABLE_NAME, new[] { "id", "Name" }, " Name = '" + portfolioName + "'", null, null, null, null);
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
cursor.MoveToNext();
|
||||
|
@ -100,19 +91,19 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
|
|||
|
||||
public void DeletePositionById(long positionId)
|
||||
{
|
||||
_db.Delete(POSITION_TABLE_NAME, "id = " + positionId, null);
|
||||
Db.Delete(POSITION_TABLE_NAME, "id = " + positionId, null);
|
||||
}
|
||||
|
||||
public Position GetPositionById(long positionId)
|
||||
{
|
||||
Position position = null;
|
||||
|
||||
var cursor = _db.Query(POSITION_TABLE_NAME, new[] { "id", "Ticker", "Shares", "PricePerShare" }, " id = " + positionId, null, null, null, null);
|
||||
var cursor = Db.Query(POSITION_TABLE_NAME, new[] { "id", "Ticker", "Shares", "PricePerShare" }, " id = " + positionId, null, null, null, null);
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
while (cursor.MoveToNext())
|
||||
{
|
||||
position= new Position(cursor.GetInt(0));
|
||||
position = new Position(cursor.GetInt(0));
|
||||
position.Ticker = cursor.GetString(1);
|
||||
position.Shares = Convert.ToDecimal(cursor.GetFloat(2));
|
||||
position.PricePerShare = Convert.ToDecimal(cursor.GetFloat(3));
|
||||
|
@ -126,7 +117,7 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
|
|||
{
|
||||
var list = new List<Position>();
|
||||
|
||||
var cursor = _db.Query(POSITION_TABLE_NAME, new[] { "id", "Ticker", "Shares", "PricePerShare" }, " ContainingPortfolioID = " + portfolioId, null, null, null, null);
|
||||
var cursor = Db.Query(POSITION_TABLE_NAME, new[] { "id", "Ticker", "Shares", "PricePerShare" }, " ContainingPortfolioID = " + portfolioId, null, null, null, null);
|
||||
if (cursor.Count > 0)
|
||||
{
|
||||
while (cursor.MoveToNext())
|
||||
|
@ -157,23 +148,23 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
|
|||
private void UpdateExistingPortfolio(Portfolio portfolio)
|
||||
{
|
||||
var portfolioID = portfolio.ID ?? -1;
|
||||
Log.E("UpdateExistingPortfolio", "Portfolios updated: " + _db.Update(PORTFOLIO_TABLE_NAME, GetPortfolioContentValues(portfolio), "id = " + portfolioID, null));
|
||||
Log.Error("UpdateExistingPortfolio", "Portfolios updated: " + Db.Update(PORTFOLIO_TABLE_NAME, GetPortfolioContentValues(portfolio), "id = " + portfolioID, null));
|
||||
}
|
||||
|
||||
private void InsertNewPortfolio(Portfolio portfolio)
|
||||
{
|
||||
Log.E("InsertNewPortfolio", "Portfolios inserted: " + _db.Insert(PORTFOLIO_TABLE_NAME, null, GetPortfolioContentValues(portfolio)));
|
||||
Log.Error("InsertNewPortfolio", "Portfolios inserted: " + Db.Insert(PORTFOLIO_TABLE_NAME, null, GetPortfolioContentValues(portfolio)));
|
||||
}
|
||||
|
||||
private void UpdateExistingPosition(Position position)
|
||||
{
|
||||
var positionID = position.ID ?? -1;
|
||||
Log.E("UpdateExistingPosition", "Positions updated: " + _db.Update(POSITION_TABLE_NAME, GetPositionContentValues(position), "id = " + positionID, null));
|
||||
Log.Error("UpdateExistingPosition", "Positions updated: " + Db.Update(POSITION_TABLE_NAME, GetPositionContentValues(position), "id = " + positionID, null));
|
||||
}
|
||||
|
||||
private void InsertNewPosition(Position position)
|
||||
{
|
||||
Log.E("InsertNewPosition", "Positions inserted: " + _db.Insert(POSITION_TABLE_NAME, null, GetPositionContentValues(position)));
|
||||
Log.Error("InsertNewPosition", "Positions inserted: " + Db.Insert(POSITION_TABLE_NAME, null, GetPositionContentValues(position)));
|
||||
}
|
||||
|
||||
private static ContentValues GetPortfolioContentValues(Portfolio portfolio)
|
||||
|
@ -192,41 +183,5 @@ namespace MonoStockPortfolio.Core.PortfolioRepositories
|
|||
positionValues.Put("ContainingPortfolioID", position.ContainingPortfolioID);
|
||||
return positionValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private class OpenHelper : SQLiteOpenHelper
|
||||
{
|
||||
public OpenHelper(Context context, string name, SQLiteDatabase.ICursorFactory factory, int version)
|
||||
: base(context, name, factory, version)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCreate(SQLiteDatabase db)
|
||||
{
|
||||
db.ExecSQL("CREATE TABLE " + PORTFOLIO_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT)");
|
||||
db.ExecSQL("CREATE TABLE " + POSITION_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, Ticker TEXT, Shares REAL, PricePerShare REAL, ContainingPortfolioID INT)");
|
||||
|
||||
db.ExecSQL("INSERT INTO " + PORTFOLIO_TABLE_NAME + " (Name) VALUES ('Sample portfolio')");
|
||||
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('GOOG', '500', '593.97', 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 ('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 ('VZ', '500', '35.78', 1)");
|
||||
db.ExecSQL("INSERT INTO " + POSITION_TABLE_NAME + " (Ticker, Shares, PricePerShare, ContainingPortfolioID) VALUES ('T', '500', '29.38', 1)");
|
||||
}
|
||||
|
||||
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
||||
{
|
||||
Log.W("Upgrade", "Nothing to upgrade");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace MonoStockPortfolio.Core.Services
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.E("GetDetailedItems", ex.ToString());
|
||||
Log.Error("GetDetailedItems", ex.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
38
MonoStockPortfolio.Core/StockData/CsvParser.cs
Normal file
38
MonoStockPortfolio.Core/StockData/CsvParser.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Android.Util;
|
||||
|
||||
namespace MonoStockPortfolio.Core.StockData
|
||||
{
|
||||
public class CsvParser
|
||||
{
|
||||
public static IEnumerable<string[]> ParseCsvIntoStockQuotes(string csvText)
|
||||
{
|
||||
using (var sr = new StringReader(csvText))
|
||||
{
|
||||
var lines = new List<string[]>();
|
||||
|
||||
try
|
||||
{
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
var tokens = line.Split(',');
|
||||
for (int i = 0; i < tokens.Length; i++)
|
||||
{
|
||||
tokens[i] = tokens[i].Trim('\"');
|
||||
}
|
||||
lines.Add(tokens);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.Error("ParseCSV", "Error in retrieving/parsing stock information");
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
MonoStockPortfolio.Core/StockData/GoogleStockDataProvider.cs
Normal file
106
MonoStockPortfolio.Core/StockData/GoogleStockDataProvider.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using MonoStockPortfolio.Entities;
|
||||
|
||||
namespace MonoStockPortfolio.Core.StockData
|
||||
{
|
||||
public class GoogleStockDataProvider : IStockDataProvider
|
||||
{
|
||||
private const string BASE_URL = "http://www.google.com/finance/info?infotype=infoquoteall&q=";
|
||||
/*
|
||||
http://code.google.com/p/qsb-mac-plugins/source/browse/trunk/stock-quoter/trunk/StockQuoter.py?r=4
|
||||
The Google Finance feed can return some or all of the following keys:
|
||||
|
||||
avvo * Average volume (float with multiplier, like '3.54M')
|
||||
beta * Beta (float)
|
||||
c * Amount of change while open (float)
|
||||
ccol * (unknown) (chars)
|
||||
cl Last perc. change
|
||||
cp * Change perc. while open (float)
|
||||
e * Exchange (text, like 'NASDAQ')
|
||||
ec * After hours last change from close (float)
|
||||
eccol * (unknown) (chars)
|
||||
ecp * After hours last chage perc. from close (float)
|
||||
el * After. hours last quote (float)
|
||||
el_cur * (unknown) (float)
|
||||
elt After hours last quote time (unknown)
|
||||
eo * Exchange Open (0 or 1)
|
||||
eps * Earnings per share (float)
|
||||
fwpe Forward PE ratio (float)
|
||||
hi * Price high (float)
|
||||
hi52 * 52 weeks high (float)
|
||||
id * Company id (identifying number)
|
||||
l * Last value while open (float)
|
||||
l_cur * Last value at close (like 'l')
|
||||
lo * Price low (float)
|
||||
lo52 * 52 weeks low (float)
|
||||
lt Last value date/time
|
||||
ltt Last trade time (Same as "lt" without the data)
|
||||
mc * Market cap. (float with multiplier, like '123.45B')
|
||||
name * Company name (text)
|
||||
op * Open price (float)
|
||||
pe * PE ratio (float)
|
||||
t * Ticker (text)
|
||||
type * Type (i.e. 'Company')
|
||||
vo * Volume (float with multiplier, like '3.54M')
|
||||
*/
|
||||
|
||||
public IEnumerable<StockQuote> GetStockQuotes(IEnumerable<string> tickers)
|
||||
{
|
||||
var tickerCsv = string.Join(",", tickers.ToArray());
|
||||
var url = BASE_URL + tickerCsv;
|
||||
var jsonResults = ScrapeUrl(url).Split('}');
|
||||
|
||||
return jsonResults.Select(MapJsonToStockitems);
|
||||
}
|
||||
|
||||
protected StockQuote MapJsonToStockitems(string jsonResults)
|
||||
{
|
||||
using(var sr = new StringReader(jsonResults))
|
||||
{
|
||||
var sq = new StockQuote();
|
||||
string line;
|
||||
while((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if(line.StartsWith(",\"t\""))
|
||||
{
|
||||
sq.Ticker = line.Replace(",\"t\" : ", "").Trim().Trim('"');
|
||||
continue;
|
||||
}
|
||||
if(line.StartsWith(",\"c\""))
|
||||
{
|
||||
sq.Change = decimal.Parse(line.Replace(",\"c\" : ", "").Trim().Trim('"'));
|
||||
continue;
|
||||
}
|
||||
if(line.StartsWith(",\"l\""))
|
||||
{
|
||||
sq.LastTradePrice = decimal.Parse(line.Replace(",\"l\" : ", "").Trim().Trim('"'));
|
||||
continue;
|
||||
}
|
||||
if(line.StartsWith(",\"ltt\""))
|
||||
{
|
||||
sq.LastTradeTime = line.Replace(",\"ltt\":", "").Trim().Trim('"').Replace("EST","").Trim();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return sq;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ScrapeUrl(string url)
|
||||
{
|
||||
string resultCsv;
|
||||
var req = WebRequest.Create(url);
|
||||
var resp = req.GetResponse();
|
||||
using (var sr = new StreamReader(resp.GetResponseStream()))
|
||||
{
|
||||
resultCsv = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
}
|
||||
return resultCsv;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using FileHelpers;
|
||||
|
||||
namespace MonoStockPortfolio.Core.StockData
|
||||
{
|
||||
[DelimitedRecord(",")]
|
||||
public class YahooFinanceStockData
|
||||
{
|
||||
[FieldQuoted(QuoteMode.OptionalForBoth)]
|
||||
public string Ticker;
|
||||
|
||||
public decimal LastTradePrice;
|
||||
|
||||
[FieldQuoted(QuoteMode.OptionalForBoth)]
|
||||
public string Name;
|
||||
|
||||
public string Volume;
|
||||
|
||||
public decimal Change;
|
||||
|
||||
[FieldQuoted(QuoteMode.OptionalForBoth)]
|
||||
public string LastTradeTime;
|
||||
|
||||
[FieldQuoted(QuoteMode.OptionalForBoth)]
|
||||
public string RealTimeLastTradeWithTime;
|
||||
|
||||
[FieldQuoted(QuoteMode.OptionalForBoth)]
|
||||
public string ChangeRealTime;
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Android.Util;
|
||||
using FileHelpers;
|
||||
using MonoStockPortfolio.Entities;
|
||||
|
||||
namespace MonoStockPortfolio.Core.StockData
|
||||
{
|
||||
public class YahooStockDataProvider : IStockDataProvider
|
||||
{
|
||||
private const string LAST_TRADE_PRICE_ONLY = "l1";
|
||||
private const string NAME = "n";
|
||||
private const string VOLUME = "v";
|
||||
private const string TICKER_SYMBOL = "s";
|
||||
private const string CHANGE = "c1";
|
||||
private const string LAST_TRADE_TIME = "t1";
|
||||
private const string REAL_TIME_LAST_TRADE_WITH_TIME = "k1";
|
||||
private const string REAL_TIME_CHANGE = "c6";
|
||||
|
||||
// http://www.gummy-stuff.org/Yahoo-data.htm
|
||||
// http://finance.yahoo.com/d/quotes.csv?s= a BUNCH of
|
||||
// STOCK SYMBOLS separated by "+" &f=a bunch of special tags
|
||||
public IEnumerable<StockQuote> GetStockQuotes(IEnumerable<string> tickers)
|
||||
{
|
||||
string url = "http://finance.yahoo.com/d/quotes.csv?s=";
|
||||
url += string.Join("+", tickers.ToArray());
|
||||
url += "&f=";
|
||||
url += TICKER_SYMBOL;
|
||||
url += LAST_TRADE_PRICE_ONLY;
|
||||
url += NAME;
|
||||
url += VOLUME;
|
||||
url += CHANGE;
|
||||
url += LAST_TRADE_TIME;
|
||||
url += REAL_TIME_LAST_TRADE_WITH_TIME;
|
||||
url += REAL_TIME_CHANGE;
|
||||
|
||||
string resultCsv = ScrapeUrl(url);
|
||||
|
||||
var yahooQuoteData = ParseCsvIntoStockQuotes(resultCsv);
|
||||
|
||||
foreach (var quote in yahooQuoteData)
|
||||
{
|
||||
yield return MapYahooData(quote);
|
||||
}
|
||||
}
|
||||
|
||||
private static StockQuote MapYahooData(YahooFinanceStockData data)
|
||||
{
|
||||
if(data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var stock = new StockQuote();
|
||||
stock.Name = data.Name;
|
||||
stock.LastTradePrice = data.LastTradePrice;
|
||||
stock.Ticker = data.Ticker;
|
||||
stock.Volume = data.Volume;
|
||||
stock.Change = data.Change;
|
||||
stock.LastTradeTime = data.LastTradeTime;
|
||||
stock.RealTimeLastTradePrice = decimal.Parse(data.RealTimeLastTradeWithTime
|
||||
.Replace("<b>", "")
|
||||
.Replace("</b>", "")
|
||||
.Replace("N/A -", "")
|
||||
.Trim()
|
||||
);
|
||||
stock.ChangeRealTime = data.ChangeRealTime;
|
||||
return stock;
|
||||
}
|
||||
|
||||
private static IList<YahooFinanceStockData> ParseCsvIntoStockQuotes(string csv)
|
||||
{
|
||||
var engine = new FileHelperEngine(typeof(YahooFinanceStockData));
|
||||
var stockQuotes = engine.ReadString(csv) as YahooFinanceStockData[];
|
||||
if(stockQuotes == null)
|
||||
{
|
||||
throw new ArgumentException("Could not parse CSV input");
|
||||
}
|
||||
return stockQuotes;
|
||||
}
|
||||
|
||||
private static string ScrapeUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
string resultCsv;
|
||||
var req = WebRequest.Create(url);
|
||||
var resp = req.GetResponse();
|
||||
using (var sr = new StreamReader(resp.GetResponseStream()))
|
||||
{
|
||||
resultCsv = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
}
|
||||
return resultCsv;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.E("ScrapeUrlException", ex.ToString());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
|
|
@ -3,22 +3,22 @@ namespace MonoStockPortfolio.Entities
|
|||
public enum StockDataItem
|
||||
{
|
||||
[StringValue("Change")]
|
||||
Change,
|
||||
Change = 0,
|
||||
[StringValue("Gain/Loss")]
|
||||
GainLoss,
|
||||
GainLoss = 1,
|
||||
[StringValue("Ticker")]
|
||||
Ticker,
|
||||
Ticker = 2,
|
||||
[StringValue("Time")]
|
||||
Time,
|
||||
Time = 3,
|
||||
[StringValue("Volume")]
|
||||
Volume,
|
||||
Volume = 4,
|
||||
[StringValue("Price")]
|
||||
LastTradePrice,
|
||||
LastTradePrice = 5,
|
||||
[StringValue("Price-RT")]
|
||||
RealTimeLastTradeWithTime,
|
||||
RealTimeLastTradeWithTime = 6,
|
||||
[StringValue("Change-RT")]
|
||||
ChangeRealTime,
|
||||
ChangeRealTime = 7,
|
||||
[StringValue("Gain/Loss-RT")]
|
||||
GainLossRealTime
|
||||
GainLossRealTime = 8
|
||||
}
|
||||
}
|
47
MonoStockPortfolio.Tests/CsvParserTests.cs
Normal file
47
MonoStockPortfolio.Tests/CsvParserTests.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System.Linq;
|
||||
using MonoStockPortfolio.Core.StockData;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoStockPortfolio.Tests
|
||||
{
|
||||
public class CsvParserTests
|
||||
{
|
||||
[Fact]
|
||||
public void Can_parse_a_single_line_with_a_single_token()
|
||||
{
|
||||
var line = "XIN";
|
||||
var result = CsvParser.ParseCsvIntoStockQuotes(line);
|
||||
|
||||
Assert.Equal(result.Count(), 1);
|
||||
Assert.Equal(result.First()[0], "XIN");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_parse_two_lines_with_a_single_token_each()
|
||||
{
|
||||
var line = "XIN\nMSFT";
|
||||
var result = CsvParser.ParseCsvIntoStockQuotes(line);
|
||||
|
||||
Assert.Equal(result.Count(), 2);
|
||||
Assert.Equal(result.First()[0], "XIN");
|
||||
Assert.Equal(result.ElementAt(1)[0], "MSFT");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_parse_a_more_complex_set()
|
||||
{
|
||||
var line = @"""XIN"",2.41,""Xinyuan Real Esta"",269244,-0.03,""4:00pm"",""N/A - <b>2.41</b>"",""-0.03""";
|
||||
var result = CsvParser.ParseCsvIntoStockQuotes(line);
|
||||
|
||||
Assert.Equal(result.Count(), 1);
|
||||
Assert.Equal(result.First()[0], "XIN");
|
||||
Assert.Equal(result.First()[1], "2.41");
|
||||
Assert.Equal(result.First()[2], "Xinyuan Real Esta");
|
||||
Assert.Equal(result.First()[3], "269244");
|
||||
Assert.Equal(result.First()[4], "-0.03");
|
||||
Assert.Equal(result.First()[5], "4:00pm");
|
||||
Assert.Equal(result.First()[6], "N/A - <b>2.41</b>");
|
||||
Assert.Equal(result.First()[7], "-0.03");
|
||||
}
|
||||
}
|
||||
}
|
170
MonoStockPortfolio.Tests/GoogleStockQuoteTests.cs
Normal file
170
MonoStockPortfolio.Tests/GoogleStockQuoteTests.cs
Normal file
|
@ -0,0 +1,170 @@
|
|||
using MonoStockPortfolio.Core.StockData;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoStockPortfolio.Tests
|
||||
{
|
||||
public class GoogleStockQuoteTests : GoogleStockDataProvider
|
||||
{
|
||||
#region ExampleJson : Example Json Result
|
||||
private string ExampleJson =
|
||||
@"
|
||||
// [ {
|
||||
""id"": ""720780""
|
||||
,""t"" : ""XIN""
|
||||
,""e"" : ""NYSE""
|
||||
,""l"" : ""2.41""
|
||||
,""l_cur"" : ""2.41""
|
||||
,""s"": ""0""
|
||||
,""ltt"":""4:00PM EST""
|
||||
,""lt"" : ""Feb 4, 4:00PM EST""
|
||||
,""c"" : ""-0.03""
|
||||
,""cp"" : ""-1.23""
|
||||
,""ccol"" : ""chr""
|
||||
,""eo"" : """"
|
||||
,""delay"": """"
|
||||
,""op"" : ""2.45""
|
||||
,""hi"" : ""2.45""
|
||||
,""lo"" : ""2.39""
|
||||
,""vo"" : ""269,244.00""
|
||||
,""avvo"" : ""352,270.00""
|
||||
,""hi52"" : ""4.30""
|
||||
,""lo52"" : ""2.20""
|
||||
,""mc"" : ""182.78M""
|
||||
,""pe"" : ""3.47""
|
||||
,""fwpe"" : """"
|
||||
,""beta"" : ""1.30""
|
||||
,""eps"" : ""0.69""
|
||||
,""name"" : ""Xinyuan Real Estate Co., Ltd. (ADR)""
|
||||
,""type"" : ""Company""
|
||||
}
|
||||
,{
|
||||
""id"": ""358464""
|
||||
,""t"" : ""MSFT""
|
||||
,""e"" : ""NASDAQ""
|
||||
,""l"" : ""27.77""
|
||||
,""l_cur"" : ""27.77""
|
||||
,""s"": ""2""
|
||||
,""ltt"":""4:01PM EST""
|
||||
,""lt"" : ""Feb 4, 4:01PM EST""
|
||||
,""c"" : ""+0.12""
|
||||
,""cp"" : ""0.43""
|
||||
,""ccol"" : ""chg""
|
||||
,""el"": ""27.72""
|
||||
,""el_cur"": ""27.72""
|
||||
,""elt"" : ""Feb 4, 7:39PM EST""
|
||||
,""ec"" : ""-0.05""
|
||||
,""ecp"" : ""-0.18""
|
||||
,""eccol"" : ""chr""
|
||||
,""div"" : ""0.16""
|
||||
,""yld"" : ""2.30""
|
||||
,""eo"" : """"
|
||||
,""delay"": """"
|
||||
,""op"" : ""27.73""
|
||||
,""hi"" : ""27.84""
|
||||
,""lo"" : ""27.51""
|
||||
,""vo"" : ""40.42M""
|
||||
,""avvo"" : ""55.50M""
|
||||
,""hi52"" : ""31.58""
|
||||
,""lo52"" : ""22.73""
|
||||
,""mc"" : ""233.33B""
|
||||
,""pe"" : ""11.77""
|
||||
,""fwpe"" : """"
|
||||
,""beta"" : ""1.06""
|
||||
,""eps"" : ""2.36""
|
||||
,""name"" : ""Microsoft Corporation""
|
||||
,""type"" : ""Company""
|
||||
}
|
||||
,{
|
||||
""id"": ""22144""
|
||||
,""t"" : ""AAPL""
|
||||
,""e"" : ""NASDAQ""
|
||||
,""l"" : ""346.50""
|
||||
,""l_cur"" : ""346.50""
|
||||
,""s"": ""2""
|
||||
,""ltt"":""4:02PM EST""
|
||||
,""lt"" : ""Feb 4, 4:02PM EST""
|
||||
,""c"" : ""+3.06""
|
||||
,""cp"" : ""0.89""
|
||||
,""ccol"" : ""chg""
|
||||
,""el"": ""346.48""
|
||||
,""el_cur"": ""346.48""
|
||||
,""elt"" : ""Feb 4, 7:59PM EST""
|
||||
,""ec"" : ""-0.02""
|
||||
,""ecp"" : ""-0.01""
|
||||
,""eccol"" : ""chr""
|
||||
,""div"" : """"
|
||||
,""yld"" : """"
|
||||
,""eo"" : """"
|
||||
,""delay"": """"
|
||||
,""op"" : ""343.76""
|
||||
,""hi"" : ""346.70""
|
||||
,""lo"" : ""343.51""
|
||||
,""vo"" : ""11.49M""
|
||||
,""avvo"" : ""15.58M""
|
||||
,""hi52"" : ""348.60""
|
||||
,""lo52"" : ""190.85""
|
||||
,""mc"" : ""319.22B""
|
||||
,""pe"" : ""19.35""
|
||||
,""fwpe"" : """"
|
||||
,""beta"" : ""1.38""
|
||||
,""eps"" : ""17.91""
|
||||
,""name"" : ""Apple Inc.""
|
||||
,""type"" : ""Company""
|
||||
}
|
||||
]
|
||||
";
|
||||
#endregion
|
||||
|
||||
private string[] SplitResults
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExampleJson.Split('}');
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_ticker()
|
||||
{
|
||||
var results = base.MapJsonToStockitems(SplitResults[0]);
|
||||
Assert.Equal(results.Ticker,"XIN");
|
||||
results = base.MapJsonToStockitems(SplitResults[1]);
|
||||
Assert.Equal(results.Ticker,"MSFT");
|
||||
results = base.MapJsonToStockitems(SplitResults[2]);
|
||||
Assert.Equal(results.Ticker,"AAPL");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_change()
|
||||
{
|
||||
var results = base.MapJsonToStockitems(SplitResults[0]);
|
||||
Assert.Equal(results.Change, -0.03M);
|
||||
results = base.MapJsonToStockitems(SplitResults[1]);
|
||||
Assert.Equal(results.Change, 0.12M);
|
||||
results = base.MapJsonToStockitems(SplitResults[2]);
|
||||
Assert.Equal(results.Change, 3.06M);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_last_price()
|
||||
{
|
||||
var results = base.MapJsonToStockitems(SplitResults[0]);
|
||||
Assert.Equal(results.LastTradePrice, 2.41M);
|
||||
results = base.MapJsonToStockitems(SplitResults[1]);
|
||||
Assert.Equal(results.LastTradePrice, 27.77M);
|
||||
results = base.MapJsonToStockitems(SplitResults[2]);
|
||||
Assert.Equal(results.LastTradePrice, 346.50M);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_time()
|
||||
{
|
||||
var results = base.MapJsonToStockitems(SplitResults[0]);
|
||||
Assert.Equal(results.LastTradeTime, "4:00PM");
|
||||
results = base.MapJsonToStockitems(SplitResults[1]);
|
||||
Assert.Equal(results.LastTradeTime, "4:01PM");
|
||||
results = base.MapJsonToStockitems(SplitResults[2]);
|
||||
Assert.Equal(results.LastTradeTime, "4:02PM");
|
||||
}
|
||||
}
|
||||
}
|
86
MonoStockPortfolio.Tests/MonoStockPortfolio.Tests.csproj
Normal file
86
MonoStockPortfolio.Tests/MonoStockPortfolio.Tests.csproj
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MonoStockPortfolio.Tests</RootNamespace>
|
||||
<AssemblyName>MonoStockPortfolio.Tests</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Core">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit">
|
||||
<HintPath>..\libs\xunit.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CsvParserTests.cs" />
|
||||
<Compile Include="GoogleStockQuoteTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MonoStockPortfolio.Core\MonoStockPortfolio.Core.csproj">
|
||||
<Project>{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}</Project>
|
||||
<Name>MonoStockPortfolio.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MonoStockPortfolio.Entities\MonoStockPortfolio.Entities.csproj">
|
||||
<Project>{05A57650-3B41-46FF-9EAD-9112B5EFBEED}</Project>
|
||||
<Name>MonoStockPortfolio.Entities</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MonoStockPortfolio\MonoStockPortfolio.csproj">
|
||||
<Project>{E23D8575-CE4E-4716-B9C7-70115D23ADBB}</Project>
|
||||
<Name>MonoStockPortfolio</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PostSharp.Custom.targets" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
6
MonoStockPortfolio.Tests/PostSharp.Custom.targets
Normal file
6
MonoStockPortfolio.Tests/PostSharp.Custom.targets
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PostSharpAssemblyBindingPolicySet>Silverlight20</PostSharpAssemblyBindingPolicySet>
|
||||
</PropertyGroup>
|
||||
</Project>
|
29
MonoStockPortfolio.Tests/Properties/AssemblyInfo.cs
Normal file
29
MonoStockPortfolio.Tests/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MonoStockPortfolio.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("MonoStockPortfolio.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -8,15 +8,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{643BA3D4-E
|
|||
libs\FileHelpers.dll = libs\FileHelpers.dll
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{4EE7F6AD-B8A9-4402-800E-E4C8AE0FF8FB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
assets\UInotes.txt = assets\UInotes.txt
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoStockPortfolio.Core", "MonoStockPortfolio.Core\MonoStockPortfolio.Core.csproj", "{251E7BB4-CFE2-4DE4-9E2A-AAE1AF41C8CB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoStockPortfolio.Entities", "MonoStockPortfolio.Entities\MonoStockPortfolio.Entities.csproj", "{05A57650-3B41-46FF-9EAD-9112B5EFBEED}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoStockPortfolio.Tests", "MonoStockPortfolio.Tests\MonoStockPortfolio.Tests.csproj", "{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -35,6 +32,10 @@ Global
|
|||
{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.Build.0 = Release|Any CPU
|
||||
{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C2797FAB-AFAB-49F6-9131-FC9BF03CAB9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
70
MonoStockPortfolio/Activites/ConfigActivity.cs
Normal file
70
MonoStockPortfolio/Activites/ConfigActivity.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using MonoStockPortfolio.Core.Config;
|
||||
using MonoStockPortfolio.Entities;
|
||||
using MonoStockPortfolio.Framework;
|
||||
using MonoStockPortfolio.Core;
|
||||
|
||||
namespace MonoStockPortfolio.Activites
|
||||
{
|
||||
[Activity(Label = "Config")]
|
||||
public class ConfigActivity : PreferenceActivity
|
||||
{
|
||||
[IoC] private IConfigRepository _repo;
|
||||
private StockItemPreference[] _stockItemsConfig;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
AddPreferencesFromResource(Resource.Layout.config);
|
||||
|
||||
_stockItemsConfig = StockItemPreference.BuildList(_repo.GetStockItems()).ToArray();
|
||||
|
||||
var customPref = FindPreference("customStockItems");
|
||||
customPref.PreferenceClick += customPref_PreferenceClick;
|
||||
}
|
||||
|
||||
bool customPref_PreferenceClick(Preference preference)
|
||||
{
|
||||
IEnumerable<char>[] stockItemsDisplay = _stockItemsConfig.OrderBy(i => i.StockDataItem).Select(i => i.StockDataItem.GetStringValue()).ToArray();
|
||||
bool[] allitemschecked = _stockItemsConfig.OrderBy(i => i.StockDataItem).Select(i => i.IsChecked).ToArray();
|
||||
|
||||
var dialog = new AlertDialog.Builder(this);
|
||||
dialog.SetMultiChoiceItems(stockItemsDisplay, allitemschecked, clickCallback);
|
||||
dialog.SetTitle("Select columns");
|
||||
dialog.SetPositiveButton("Save", okCallback);
|
||||
dialog.Create().Show();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void okCallback(object sender, DialogClickEventArgs e)
|
||||
{
|
||||
var list = _stockItemsConfig.Where(i => i.IsChecked).Select(i => i.StockDataItem).ToList();
|
||||
_repo.UpdateStockItems(list);
|
||||
}
|
||||
|
||||
private void clickCallback(object sender, DialogMultiChoiceClickEventArgs e)
|
||||
{
|
||||
_stockItemsConfig[e.Which].IsChecked = e.IsChecked;
|
||||
}
|
||||
|
||||
public static string ClassName { get { return "monostockportfolio.activites.ConfigActivity"; } }
|
||||
|
||||
private class StockItemPreference
|
||||
{
|
||||
public static IEnumerable<StockItemPreference> BuildList(IEnumerable<StockDataItem> checkedItems)
|
||||
{
|
||||
var allitems = StockDataItem.Change.GetValues<StockDataItem>();
|
||||
|
||||
return allitems.Select(item => new StockItemPreference {StockDataItem = item, IsChecked = checkedItems.Contains(item)});
|
||||
}
|
||||
public StockDataItem StockDataItem { get; private set; }
|
||||
public bool IsChecked { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
SetContentView(Resource.layout.addportfolio);
|
||||
SetContentView(Resource.Layout.addportfolio);
|
||||
|
||||
WireUpEvents();
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace MonoStockPortfolio.Activites
|
|||
public static string Extra_PortfolioID { get { return "monoStockPortfolio.EditPortfolioActivity.PortfolioID"; } }
|
||||
public long ThisPortfolioId { get { return Intent.GetLongExtra(Extra_PortfolioID, -1); } }
|
||||
|
||||
protected Button SaveButton { get { return FindViewById<Button>(Resource.id.btnSave); } }
|
||||
protected EditText PortfolioName { get { return FindViewById<EditText>(Resource.id.portfolioName); } }
|
||||
protected Button SaveButton { get { return FindViewById<Button>(Resource.Id.btnSave); } }
|
||||
protected EditText PortfolioName { get { return FindViewById<EditText>(Resource.Id.portfolioName); } }
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
SetContentView(Resource.layout.addposition);
|
||||
SetContentView(Resource.Layout.addposition);
|
||||
|
||||
var positionId = ThisPositionId;
|
||||
if (positionId != -1)
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace MonoStockPortfolio.Activites
|
|||
public static string Extra_PositionID { get { return "monoStockPortfolio.EditPositionActivity.PositionID"; } }
|
||||
public long ThisPositionId { get { return Intent.GetLongExtra(Extra_PositionID, -1); } }
|
||||
|
||||
protected EditText TickerTextBox { get { return FindViewById<EditText>(Resource.id.addPositionTicker); } }
|
||||
protected EditText PriceTextBox { get { return FindViewById<EditText>(Resource.id.addPositionPrice); } }
|
||||
protected EditText SharesTextBox { get { return FindViewById<EditText>(Resource.id.addPositionShares); } }
|
||||
protected Button SaveButton { get { return FindViewById<Button>(Resource.id.addPositionSaveButton); } }
|
||||
protected EditText TickerTextBox { get { return FindViewById<EditText>(Resource.Id.addPositionTicker); } }
|
||||
protected EditText PriceTextBox { get { return FindViewById<EditText>(Resource.Id.addPositionPrice); } }
|
||||
protected EditText SharesTextBox { get { return FindViewById<EditText>(Resource.Id.addPositionShares); } }
|
||||
protected Button SaveButton { get { return FindViewById<Button>(Resource.Id.addPositionSaveButton); } }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using MonoStockPortfolio.Core.PortfolioRepositories;
|
||||
using MonoStockPortfolio.Entities;
|
||||
|
@ -22,7 +23,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
SetContentView(Resource.layout.main);
|
||||
SetContentView(Resource.Layout.main);
|
||||
|
||||
RefreshList();
|
||||
|
||||
|
@ -33,7 +34,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
_portfolios = _repo.GetAllPortfolios();
|
||||
|
||||
var listAdapter = new ArrayAdapter<string>(this, Android.R.Layout.SimpleListItem1, _portfolios.Select(p => p.Name).ToList());
|
||||
var listAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, _portfolios.Select(p => p.Name).ToList());
|
||||
PortfolioListView.Adapter = listAdapter;
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,32 @@ namespace MonoStockPortfolio.Activites
|
|||
return base.OnContextItemSelected(item);
|
||||
}
|
||||
|
||||
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
{
|
||||
var configItem = menu.Add(0, 1, 1, "Config");
|
||||
configItem.SetIcon(Android.Resource.Drawable.IcMenuPreferences);
|
||||
var exitItem = menu.Add(0, 1, 1, "Exit");
|
||||
exitItem.SetIcon(Android.Resource.Drawable.IcMenuCloseClearCancel);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
switch (item.Title.ToS())
|
||||
{
|
||||
case "Config":
|
||||
var intent = new Intent();
|
||||
intent.SetClassName(this, ConfigActivity.ClassName);
|
||||
StartActivityForResult(intent, 0);
|
||||
return true;
|
||||
case "Exit":
|
||||
Finish();
|
||||
return true;
|
||||
default:
|
||||
return base.OnOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void listView_ItemClick(object sender, ItemEventArgs e)
|
||||
{
|
||||
var intent = new Intent();
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
public static string ClassName { get { return "monostockportfolio.activites.MainActivity"; } }
|
||||
|
||||
protected Button AddPortfolioButton { get { return FindViewById<Button>(Resource.id.btnAddPortfolio); } }
|
||||
protected ListView PortfolioListView { get { return FindViewById<ListView>(Resource.id.portfolioList); } }
|
||||
protected Button AddPortfolioButton { get { return FindViewById<Button>(Resource.Id.btnAddPortfolio); } }
|
||||
protected ListView PortfolioListView { get { return FindViewById<ListView>(Resource.Id.portfolioList); } }
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ namespace MonoStockPortfolio.Activites
|
|||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
SetContentView(Resource.layout.portfolio);
|
||||
SetContentView(Resource.Layout.portfolio);
|
||||
|
||||
Refresh();
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace MonoStockPortfolio.Activites
|
|||
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
{
|
||||
var item = menu.Add(0,1,1,"Refresh");
|
||||
item.SetIcon(Resource.drawable.ic_menu_refresh);
|
||||
item.SetIcon(Resource.Drawable.ic_menu_refresh);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ namespace MonoStockPortfolio.Activites
|
|||
|
||||
private void ShowMessage(string message)
|
||||
{
|
||||
var listAdapter = new ArrayAdapter<string>(this, Android.R.Layout.SimpleListItem1, new[] {message});
|
||||
var listAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, new[] { message });
|
||||
QuoteListview.Adapter = listAdapter;
|
||||
}
|
||||
|
||||
|
@ -134,10 +134,10 @@ namespace MonoStockPortfolio.Activites
|
|||
var textItem = new TextView(this);
|
||||
textItem.Text = stockDataItem.GetStringValue();
|
||||
textItem.SetWidth(cellwidth);
|
||||
textItem.SetTextColor(Resources.GetColor(Android.R.Color.Black));
|
||||
textItem.SetTextColor(Resources.GetColor(Android.Resource.Color.Black));
|
||||
QuoteListviewHeader.AddView(textItem);
|
||||
}
|
||||
QuoteListviewHeader.SetBackgroundResource(Android.R.Color.BackgroundLight);
|
||||
QuoteListviewHeader.SetBackgroundResource(Android.Resource.Color.BackgroundLight);
|
||||
}
|
||||
|
||||
public class PositionArrayAdapter : GenericArrayAdapter<PositionResultsViewModel>
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace MonoStockPortfolio.Activites
|
|||
public static string Extra_PortfolioID { get { return "monoStockPortfolio.PortfolioActivity.PortfolioID"; } }
|
||||
public long ThisPortofolioId { get { return Intent.GetLongExtra(Extra_PortfolioID, -1); } }
|
||||
|
||||
protected ListView QuoteListview { get { return FindViewById<ListView>(Resource.id.quoteListview); } }
|
||||
protected Button AddPositionButton { get { return FindViewById<Button>(Resource.id.btnAddPosition); } }
|
||||
protected LinearLayout QuoteListviewHeader { get { return FindViewById<LinearLayout>(Resource.id.quoteHeaderLayout); } }
|
||||
protected ListView QuoteListview { get { return FindViewById<ListView>(Resource.Id.quoteListview); } }
|
||||
protected Button AddPositionButton { get { return FindViewById<Button>(Resource.Id.btnAddPosition); } }
|
||||
protected LinearLayout QuoteListviewHeader { get { return FindViewById<LinearLayout>(Resource.Id.quoteHeaderLayout); } }
|
||||
}
|
||||
}
|
|
@ -5,18 +5,18 @@ namespace MonoStockPortfolio.Framework
|
|||
{
|
||||
public class IoCAttribute : LocationInterceptionAspect
|
||||
{
|
||||
public override void OnGetValue(LocationInterceptionArgs args)
|
||||
public sealed override void OnGetValue(LocationInterceptionArgs args)
|
||||
{
|
||||
if (ServiceLocator.Context == null)
|
||||
{
|
||||
var activityContext= (Context)args.Instance;
|
||||
var activityContext = (Context)args.Instance;
|
||||
ServiceLocator.Context = activityContext.ApplicationContext.ApplicationContext;
|
||||
}
|
||||
|
||||
var locationType = args.Location.LocationType;
|
||||
var instantiation = ServiceLocator.Get(locationType);
|
||||
|
||||
if(instantiation != null)
|
||||
if (instantiation != null)
|
||||
{
|
||||
args.SetNewValue(instantiation);
|
||||
}
|
||||
|
|
104
MonoStockPortfolio/Framework/IttyBittyIoC.cs
Normal file
104
MonoStockPortfolio/Framework/IttyBittyIoC.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MonoStockPortfolio.Framework
|
||||
{
|
||||
public static class IttyBittyIoC
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Constructor)]
|
||||
public class InjectionConstructorAttribute : Attribute
|
||||
{ }
|
||||
|
||||
private enum DependencyType
|
||||
{
|
||||
None = 0, // Type is unset
|
||||
Delegate, // A builder function
|
||||
Instance, // A specific instance
|
||||
Singleton, // Dynamically created singleton
|
||||
Transient // Dynamically created transient object
|
||||
}
|
||||
|
||||
private class DependencyInfo
|
||||
{
|
||||
public object Dependency { get; private set; }
|
||||
public DependencyType DependencyType { get; private set; }
|
||||
|
||||
public DependencyInfo(DependencyType dependencyType, object dependency)
|
||||
{
|
||||
DependencyType = dependencyType;
|
||||
Dependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly static IDictionary<Type, DependencyInfo> dependencies = new Dictionary<Type, DependencyInfo>();
|
||||
private readonly static IDictionary<Type, object> instances = new Dictionary<Type, object>();
|
||||
|
||||
public static void Register<TContract>(TContract instance)
|
||||
{
|
||||
dependencies[typeof(TContract)] = new DependencyInfo(DependencyType.Instance, instance);
|
||||
instances[typeof(TContract)] = instance;
|
||||
}
|
||||
|
||||
public static void Register<TContract, TImplementation>()
|
||||
{
|
||||
Register<TContract, TImplementation>(false);
|
||||
}
|
||||
|
||||
public static void Register<TContract, TImplementation>(bool isSingleton)
|
||||
{
|
||||
DependencyType dependencyType = isSingleton ? DependencyType.Singleton : DependencyType.Transient;
|
||||
dependencies[typeof(TContract)] = new DependencyInfo(dependencyType, typeof(TImplementation));
|
||||
}
|
||||
|
||||
public static void Register<TContract>(Func<TContract> builder)
|
||||
{
|
||||
dependencies[typeof(TContract)] = new DependencyInfo(DependencyType.Delegate, builder);
|
||||
}
|
||||
|
||||
public static TContract Resolve<TContract>()
|
||||
{
|
||||
return (TContract)Resolve(typeof(TContract));
|
||||
}
|
||||
|
||||
public static object Resolve(Type contract)
|
||||
{
|
||||
if (!dependencies.ContainsKey(contract))
|
||||
throw new InvalidOperationException(string.Format("Unable to resolve type '{0}'.", contract));
|
||||
if (instances.ContainsKey(contract))
|
||||
return instances[contract];
|
||||
var dependency = dependencies[contract];
|
||||
if (dependency.DependencyType == DependencyType.Delegate)
|
||||
return ((Delegate)dependency.Dependency).DynamicInvoke();
|
||||
|
||||
var constructorInfo = ((Type)dependency.Dependency).GetConstructors()
|
||||
.OrderByDescending(o => (o.GetCustomAttributes(typeof(InjectionConstructorAttribute), false).Count()))
|
||||
.ThenByDescending(o => (o.GetParameters().Length))
|
||||
.First();
|
||||
var parameterInfos = constructorInfo.GetParameters();
|
||||
|
||||
object instance;
|
||||
if (parameterInfos.Length == 0)
|
||||
{
|
||||
instance = Activator.CreateInstance((Type)dependency.Dependency);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parameters = new List<object>(parameterInfos.Length);
|
||||
foreach (ParameterInfo parameterInfo in parameterInfos)
|
||||
{
|
||||
parameters.Add(Resolve(parameterInfo.ParameterType));
|
||||
}
|
||||
instance = constructorInfo.Invoke(parameters.ToArray());
|
||||
}
|
||||
|
||||
if (dependency.DependencyType == DependencyType.Singleton)
|
||||
{
|
||||
instances[contract] = instance;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,35 +4,25 @@ using MonoStockPortfolio.Core.Config;
|
|||
using MonoStockPortfolio.Core.PortfolioRepositories;
|
||||
using MonoStockPortfolio.Core.Services;
|
||||
using MonoStockPortfolio.Core.StockData;
|
||||
using TinyIoC;
|
||||
|
||||
namespace MonoStockPortfolio.Framework
|
||||
{
|
||||
public static class ServiceLocator
|
||||
{
|
||||
public static Context Context { get; set; }
|
||||
private static TinyIoCContainer _container;
|
||||
|
||||
static ServiceLocator()
|
||||
{
|
||||
//IttyBittyIoC.Register(Context);
|
||||
IttyBittyIoC.Register<IStockDataProvider>(() => new GoogleStockDataProvider());
|
||||
IttyBittyIoC.Register<IPortfolioService>(() => new PortfolioService(new AndroidSqlitePortfolioRepository(Context), new GoogleStockDataProvider()));
|
||||
IttyBittyIoC.Register<IPortfolioRepository>(() => new AndroidSqlitePortfolioRepository(Context));
|
||||
IttyBittyIoC.Register<IConfigRepository>(() => new AndroidSqliteConfigRepository(Context));
|
||||
}
|
||||
|
||||
public static object Get(Type serviceType)
|
||||
{
|
||||
if (_container == null)
|
||||
{
|
||||
_container = RegisterTypes();
|
||||
}
|
||||
return _container.Resolve(serviceType);
|
||||
}
|
||||
|
||||
private static TinyIoCContainer RegisterTypes()
|
||||
{
|
||||
var container = TinyIoCContainer.Current;
|
||||
|
||||
container.Register<Context>(Context);
|
||||
container.Register<IStockDataProvider, YahooStockDataProvider>().AsMultiInstance();
|
||||
container.Register<IPortfolioService, PortfolioService>().AsMultiInstance();
|
||||
container.Register<IPortfolioRepository, AndroidSqlitePortfolioRepository>().AsMultiInstance();
|
||||
container.Register<IConfigRepository, AndroidSqliteConfigRepository>().AsMultiInstance();
|
||||
|
||||
return container;
|
||||
return IttyBittyIoC.Resolve(serviceType);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -40,7 +40,7 @@
|
|||
<Reference Include="mscorlib" />
|
||||
<Reference Include="PostSharp.SL, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b13fd38b8f9c99d7, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\libs\PostSharp.SL.dll</HintPath>
|
||||
<HintPath>..\..\..\Program Files (x86)\PostSharp 2.0\Reference Assemblies\Silverlight 3.0\PostSharp.SL.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
@ -48,6 +48,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Activites\ConfigActivity.cs" />
|
||||
<Compile Include="Activites\EditPositionActivity.designer.cs">
|
||||
<DependentUpon>EditPositionActivity.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -58,7 +59,6 @@
|
|||
<Compile Include="Framework\ActivityExtensions.cs" />
|
||||
<Compile Include="Framework\ContextExtensions.cs" />
|
||||
<Compile Include="Framework\GenericArrayAdapter.cs" />
|
||||
<Compile Include="Framework\IoCAttribute.cs" />
|
||||
<Compile Include="Activites\MainActivity.designer.cs">
|
||||
<DependentUpon>MainActivity.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -68,17 +68,16 @@
|
|||
<Compile Include="Activites\PortfolioActivity.designer.cs">
|
||||
<DependentUpon>PortfolioActivity.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Framework\IoCAttribute.cs" />
|
||||
<Compile Include="Framework\IttyBittyIoC.cs" />
|
||||
<Compile Include="Framework\ServiceLocator.cs" />
|
||||
<Compile Include="Framework\TinyIoC.cs" />
|
||||
<Compile Include="Resources\Resource.Designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Framework\StringExtensions.cs" />
|
||||
<Compile Include="Framework\FormValidator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PostSharp.Custom.targets">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="PostSharp.Custom.targets" />
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -117,15 +116,27 @@
|
|||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\config.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_menu_refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\drawable-ldpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_menu_refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_menu_refresh.png" />
|
||||
<AndroidResource Include="Resources\drawable-ldpi\ic_menu_refresh.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_menu_refresh.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-ldpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
27
MonoStockPortfolio/Resources/Resource.Designer.cs
generated
27
MonoStockPortfolio/Resources/Resource.Designer.cs
generated
|
@ -15,15 +15,15 @@ namespace MonoStockPortfolio
|
|||
public partial class Resource
|
||||
{
|
||||
|
||||
public partial class attr
|
||||
public partial class Attribute
|
||||
{
|
||||
|
||||
private attr()
|
||||
private Attribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class drawable
|
||||
public partial class Drawable
|
||||
{
|
||||
|
||||
// aapt resource value: 0x7f020000
|
||||
|
@ -32,12 +32,12 @@ namespace MonoStockPortfolio
|
|||
// aapt resource value: 0x7f020001
|
||||
public const int icon = 2130837505;
|
||||
|
||||
private drawable()
|
||||
private Drawable()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class id
|
||||
public partial class Id
|
||||
{
|
||||
|
||||
// aapt resource value: 0x7f050004
|
||||
|
@ -73,12 +73,12 @@ namespace MonoStockPortfolio
|
|||
// aapt resource value: 0x7f05000a
|
||||
public const int quoteListview = 2131034122;
|
||||
|
||||
private id()
|
||||
private Id()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class layout
|
||||
public partial class Layout
|
||||
{
|
||||
|
||||
// aapt resource value: 0x7f030000
|
||||
|
@ -88,17 +88,20 @@ namespace MonoStockPortfolio
|
|||
public const int addposition = 2130903041;
|
||||
|
||||
// aapt resource value: 0x7f030002
|
||||
public const int main = 2130903042;
|
||||
public const int config = 2130903042;
|
||||
|
||||
// aapt resource value: 0x7f030003
|
||||
public const int portfolio = 2130903043;
|
||||
public const int main = 2130903043;
|
||||
|
||||
private layout()
|
||||
// aapt resource value: 0x7f030004
|
||||
public const int portfolio = 2130903044;
|
||||
|
||||
private Layout()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class @string
|
||||
public partial class String
|
||||
{
|
||||
|
||||
// aapt resource value: 0x7f040001
|
||||
|
@ -107,7 +110,7 @@ namespace MonoStockPortfolio
|
|||
// aapt resource value: 0x7f040000
|
||||
public const int hello = 2130968576;
|
||||
|
||||
private @string()
|
||||
private String()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
9
MonoStockPortfolio/Resources/layout/config.xml
Normal file
9
MonoStockPortfolio/Resources/layout/config.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="General Settings">
|
||||
<Preference
|
||||
android:title="Stock Items"
|
||||
android:summary="Which columns do you want to see?"
|
||||
android:key="customStockItems" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -4,16 +4,11 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" android:orientation="vertical">
|
||||
<Button android:text="Add New Portfolio" android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" android:id="@+id/btnAddPortfolio" />
|
||||
|
||||
<Button android:text="Add New Portfolio" android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" android:id="@+id/btnAddPortfolio" />
|
||||
|
||||
<ListView android:id="@+id/portfolioList"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
<ListView android:id="@+id/portfolioList"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
BIN
libs/xunit.dll
Normal file
BIN
libs/xunit.dll
Normal file
Binary file not shown.
Loading…
Reference in a new issue