Skip to content

Instantly share code, notes, and snippets.

@programmation
Last active October 20, 2015 04:30
Show Gist options
  • Save programmation/3e8b253dfe7ef9e3317a to your computer and use it in GitHub Desktop.
Save programmation/3e8b253dfe7ef9e3317a to your computer and use it in GitHub Desktop.
Foundations of a skinnable app
// SkinnableApp/App.xaml
<?xml version="1.0" encoding="UTF-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SkinnableApp.App">
<Application.Resources>
<ResourceDictionary>
</ResourceDictionary>
</Application.Resources>
</Application>
// SkinnableApp/App.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Xamarin.Forms;
namespace SkinnableApp
{
public partial class App : Application
{
public App (string bundleId)
{
SetupIOC ();
SetupStyles ();
MainPage = new StartPage();
}
void SetupIOC ()
{
IOC.Container.Register<IStyleService, StyleService> ();
}
void SetupStyles ()
{
if (Resources == null) {
Resources = new ResourceDictionary ();
}
IStyleService styles = IOC.Container.Resolve<IStyleService> ();
var service = JsonConvert.DeserializeObject<StyleService> (AppState.StylesJson);
styles.Setup (service);
var output = JsonConvert.SerializeObject (styles);
Debug.WriteLine (output);
var methods = typeof(IStyleService)
.GetRuntimeMethods ()
.Where (m => !m.Name.StartsWith ("get_")) // remove auto-properties
.Where (m => !m.Name.StartsWith ("set_")) // remove auto-properties
.Where (m => !m.Name.StartsWith ("Setup")) // remove auto-properties
.ToList ();
foreach (var method in methods) {
Resources.Add (method.Name, method.Invoke (styles, null));
}
var properties = typeof(IStyleService)
.GetRuntimeProperties ();
foreach (var property in properties) {
Resources.Add (property.Name, property.GetValue (styles, null));
}
}
}
}
// SkinnableApp.iOS/AppDelegate.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
namespace SkinnableApp.iOS
{
[Register ("AppDelegate")]
public partial class AppDelegate : FormsApplicationDelegate
{
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();
var formsApp = AppStarter.Start (app, options, this);
LoadApplication (formsApp);
return base.FinishedLaunching (app, options);
}
}
}
// SkinnableAppLib.iOS/AppStarter.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
namespace SkinnableApp.iOS
{
public static class AppStarter
{
public static Application Start (UIApplication app,
NSDictionary options, FormsApplicationDelegate appDelegate)
{
LoadConfiguration ();
var bundleId = NSBundle.MainBundle.BundleIdentifier;
var formsApp = new App (bundleId);
return formsApp;
}
public static void LoadConfiguration ()
{
AppState.ResourcesJson = ReadStringAsset ("Configuration/Resources.json");
AppState.StylesJson = ReadStringAsset ("Configuration/Styles.json");
AppState.MenusJson = ReadStringAsset ("Configuration/Menus.json");
}
public static string ReadStringAsset (string path)
{
string assetText = File.ReadAllText (path);
return assetText;
}
}
}
// SkinnableApp.Droid/MainActivity.cs
using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
namespace SkinnableApp.Droid
{
[Activity (Label = "SkinnableApp.Droid",
Icon = "@drawable/icon",
MainLauncher = false,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait,
Theme = "@style/MainTheme")]
public class MainActivity : FormsApplicationActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
var formsApp = AppStarter.Start (this, bundle, Forms.Context);
LoadApplication (formsApp);
}
}
}
// SkinnableAppLib.Droid/AppStarter.cs
using System;
using System.IO;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
namespace SkinnableApp.Droid
{
public static class AppStarter
{
public static Xamarin.Forms.Application Start (FormsApplicationActivity activity, Bundle bundle, Context context)
{
LoadConfiguration (context);
var bundleId = context.PackageName;
var formsApp = new App (bundleId);
return formsApp;
}
public static void LoadConfiguration (Context context)
{
AppState.ResourcesJson = ReadStringAsset (context, "Resources.json");
AppState.StylesJson = ReadStringAsset (context, "Styles.json");
AppState.MenusJson = ReadStringAsset (context, "Menus.json");
}
public static string ReadStringAsset (Context context, string path)
{
var asset = ((Activity)context).Assets.Open (path);
string assetText;
using (var sr = new StreamReader (asset))
{
assetText = sr.ReadToEnd ();
}
return assetText;
}
}
}
// Set Configuration folder as Git Subtree in project folder
// skinnableupdateios.sh
#!/bin/sh
function help () {
echo "skinnableupdateios - simple script to keep assets in sync with designer resources"
echo ""
echo " skinnableupdateios {projectdir} {resourcedir} - {resourcedir} is resource directory in {projectdir}"
}
function dosync () {
cd $1
rsync -avh "../Configuration/$2/Configuration" "$1/Resources/"
rsync -avh "../Configuration/$2/Fonts" "$1/Resources/"
rsync -avh "../Configuration/$2/Resources/iOS/" "$1/Resources/"
}
if [ $1 ] ; then
dosync $1 $2
else
help
fi
// skinnableupdatedroid.sh
#!/bin/sh
function help () {
echo "skinnableupdatedroid - simple script to keep assets in sync with designer resources"
echo ""
echo " skinnableupdatedroid {projectdir} {resourcedir} - {resourcedir} is resource directory in {projectdir}"
}
function dosync () {
cd $1
rsync -avh "../Configuration/$2/Configuration/" "./Assets/"
rsync -avh "../Configuration/$2/Fonts/" "./Assets/"
rsync -avh "../Configuration/$2/Resources/Droid/" "./Resources/"
}
if [ $1 ] ; then
dosync $1 $2
else
help
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment