diff --git a/apps.module b/apps.module
index 056a82a..1e5c66a 100755
--- a/apps.module
+++ b/apps.module
@@ -160,3 +160,28 @@ function apps_updater_info() {
   );
 }
 
+/**
+ * Implements hook_system_theme_info()
+ * Get a list of all enabled apps, check if they have themes listed, and list them on the appearance page
+ */
+function apps_system_theme_info() {
+  $servers = func_get_args();
+  $themes = array();
+  module_load_include('inc', 'apps', 'apps.manifest');
+  $servers = !empty($servers)? $servers : array_keys(apps_servers());
+  foreach($servers as $server) {
+    $apps = apps_apps($server);
+    foreach ($apps as $k => $app) {
+      $machine_name = $app['machine_name'];
+      if($app['status'] == 1) {
+        $info = drupal_parse_info_file(drupal_get_path('module', $machine_name) . '/' . $machine_name . '.info');
+        if(isset($info['apps']['themes'])) {
+          foreach ($info['apps']['themes'] as $theme) {
+            $themes[$theme] = drupal_get_path('module', $machine_name) . '/' . $theme . '/' . $theme . '.info';
+          }
+        }
+      }
+    }
+  }
+  return $themes;
+}
diff --git a/apps.pages.inc b/apps.pages.inc
index a1a4021..efb7fc1 100755
--- a/apps.pages.inc
+++ b/apps.pages.inc
@@ -81,6 +81,14 @@ function apps_app_config_page($server_name, $app_name) {
   if($form = apps_app_callback($app, "configure form")) {
     $element[] =  drupal_get_form($form);
   }
+  $info = drupal_parse_info_file(drupal_get_path('module', $app_name) . '/' . $app_name . '.info');
+  if(isset($info['apps']['themes'])) {
+    $element[] = array(
+    '#type' => 'item',
+    '#title' => t('Themes'),
+    '#markup' => apps_app_config_themes($app_name, $info['apps']['themes']),
+    );
+  }
   return $element;
   return "$app_name has no configuration";
 }
@@ -90,6 +98,116 @@ function apps_app_config_action_redirect($server_name, $app_name) {
   $app = $apps[$app_name];
   drupal_goto(apps_app_page_path($app, 'configure'));
 }
+function apps_app_config_themes($app_name, $themes) {
+  $themes_list = list_themes();
+  $app_themes = array();
+  foreach ($themes as $theme_name) {
+    if(isset($themes_list[$theme_name])) {
+      $app_themes[$theme_name] = $themes_list[$theme_name];
+    }
+  }
+  $theme_default = variable_get('theme_default', 'bartik');
+  foreach ($app_themes as &$theme) {
+    if (!empty($theme->info['hidden'])) {
+      continue;
+    }
+    $admin_theme_options[$theme->name] = $theme->info['name'];
+    $theme->is_default = ($theme->name == $theme_default);
+
+    // Identify theme screenshot.
+    $theme->screenshot = NULL;
+    // Create a list which includes the current theme and base theme.
+    if (isset($app_themes[$theme->name]->base_theme)) {
+      $theme_keys[] = $app_themes[$theme->name]->base_theme;
+      $theme_keys[] = $theme->name;
+    }
+    else {
+      $theme_keys = array($theme->name);
+    }
+    // Look for a screenshot in the current theme or in its closest ancestor.
+    foreach (array_reverse($theme_keys) as $theme_key) {
+      if (isset($app_themes[$theme_key]) && file_exists($app_themes[$theme_key]->info['screenshot'])) {
+        $theme->screenshot = array(
+          'path' => $app_themes[$theme_key]->info['screenshot'], 
+          'alt' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])), 
+          'title' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])), 
+          'attributes' => array('class' => array('screenshot')),
+        );
+        break;
+      }
+    }
+
+    if (empty($theme->status)) {
+      // Ensure this theme is compatible with this version of core.
+      // Require the 'content' region to make sure the main page
+      // content has a common place in all themes.
+      $theme->incompatible_core = !isset($theme->info['core']) || ($theme->info['core'] != DRUPAL_CORE_COMPATIBILITY) || (!isset($theme->info['regions']['content']));
+      $theme->incompatible_php = version_compare(phpversion(), $theme->info['php']) < 0;
+    }
+    $query['token'] = drupal_get_token('system-theme-operation-link');
+    $theme->operations = array();
+    if (!empty($theme->status) || !$theme->incompatible_core && !$theme->incompatible_php) {
+      // Create the operations links.
+      $query['theme'] = $theme->name;
+      if (drupal_theme_access($theme)) {
+        $theme->operations[] = array(
+          'title' => t('Settings'), 
+          'href' => 'admin/appearance/settings/' . $theme->name, 
+          'attributes' => array('title' => t('Settings for !theme theme', array('!theme' => $theme->info['name']))),
+        );
+      }
+      if (!empty($theme->status)) {
+        if (!$theme->is_default) {
+          $theme->operations[] = array(
+            'title' => t('Disable'), 
+            'href' => 'admin/appearance/disable', 
+            'query' => $query, 
+            'attributes' => array('title' => t('Disable !theme theme', array('!theme' => $theme->info['name']))),
+          );
+          $theme->operations[] = array(
+            'title' => t('Set default'), 
+            'href' => 'admin/appearance/default', 
+            'query' => $query, 
+            'attributes' => array('title' => t('Set !theme as default theme', array('!theme' => $theme->info['name']))),
+          );
+        }
+      }
+      else {
+        $theme->operations[] = array(
+          'title' => t('Enable'), 
+          'href' => 'admin/appearance/enable', 
+          'query' => $query, 
+          'attributes' => array('title' => t('Enable !theme theme', array('!theme' => $theme->info['name']))),
+        );
+        $theme->operations[] = array(
+          'title' => t('Enable and set default'), 
+          'href' => 'admin/appearance/default', 
+          'query' => $query, 
+          'attributes' => array('title' => t('Enable !theme as default theme', array('!theme' => $theme->info['name']))),
+        );
+      }
+    }
+
+    // Add notes to default and administration theme.
+    $theme->notes = array();
+    $theme->classes = array();
+    if ($theme->is_default) {
+      $theme->classes[] = 'theme-default';
+      $theme->notes[] = t('default theme');
+    }
+
+    // Put theme into group
+    $theme_groups['app_themes'][] = $theme;
+  }
+
+  // Give group a name
+  $theme_group_titles = array(
+    'app_themes' => t('Themes provided by this app'),
+  );
+  
+  return theme('system_themes_page', array('theme_groups' => $theme_groups, 'theme_group_titles' => $theme_group_titles));
+}
+
 /**
  * callback for the app detail page
  */
@@ -147,11 +265,12 @@ function _apps_app_access($perm, $server_name, $action, $app_name) {
         return ($app['status'] === APPS_INSTALLABLE);
       case 'configure-action':
       case 'configure': 
-        return (bool) apps_app_callback($app, "configure form") || apps_app_callback($app, "demo content enabled callback");
+        $info = drupal_parse_info_file(drupal_get_path('module', $app_name) . '/' . $app_name . '.info');
+        return (bool) apps_app_callback($app, "configure form") || apps_app_callback($app, "demo content enabled callback") || isset($info['apps']['themes']);
         //not doing this now for config as it brakes going to config after install
         // we only want this to show if we are on the configure page
         return ($_GET['q'] == apps_app_page_path($app, 'configure')) &&
-        (apps_app_callback($app, "configure form") ||apps_app_callback($app, "demo content enabled callback")) ;
+        (apps_app_callback($app, "configure form") ||apps_app_callback($app, "demo content enabled callback") || isset($info['apps']['themes'])) ;
       case 'uninstall': 
         return ($app['disabled']);
     }
