diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 03c0aa4..c510741 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,8 +1,7 @@
+// $Id: CHANGELOG.txt,v 1.14 2011/01/07 23:41:22 sun Exp $
 
 Switchtheme 7.x-1.x, xxxx-xx-xx
 -------------------------------
-#871692 by sun: Fixed custom theme labels not applied on output.
-#402348 by gilgabar, sun: Fixed form validation errors with block caching.
 
 
 Switchtheme 7.x-1.0, 2010-01-07
@@ -12,7 +11,6 @@ Switchtheme 7.x-1.0, 2010-01-07
 
 Switchtheme 6.x-1.x, xxxx-xx-xx
 -------------------------------
-#986520 by RockSoup: Fixed bogus customization code in README.txt.
 #455796 by sun: Fixed query string allows to select disabled themes.
 #417120 by dereine: Fixed random theme block displays disabled themes.
 
diff --git a/README.txt b/README.txt
index cd91916..015017c 100644
--- a/README.txt
+++ b/README.txt
@@ -1,3 +1,4 @@
+/* $Id: README.txt,v 1.9 2011/01/07 23:41:22 sun Exp $ */
 
 -- SUMMARY --
 
@@ -101,7 +102,7 @@ the font size of their pages.
   which allow users to switch to pre-defined themes.  For example, using
   Drupal's l() function in page.tpl.php (without code tags):
 <code>
-print l('Red theme', $_GET['q'], array('query' => array('theme' => 'red'))); 
+print l('Red theme', $_GET['q'], array(), 'theme=red');
 </code>
 
 
diff --git a/src/EventSubscriber/InitSubscriber.php b/src/EventSubscriber/InitSubscriber.php
new file mode 100644
index 0000000..11fa3b7
--- /dev/null
+++ b/src/EventSubscriber/InitSubscriber.php
@@ -0,0 +1,37 @@
+<?php /**
+ * @file
+ * Contains \Drupal\switchtheme\EventSubscriber\InitSubscriber.
+ */
+
+namespace Drupal\switchtheme\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Drupal\switchtheme\Switchtheme;
+use Drupal\Core\Form\FormState;
+
+class InitSubscriber implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    return [ KernelEvents::REQUEST => ['onEvent', 0]];
+  }
+
+  public function onEvent() {
+    // If there is a HTTP GET parameter 'theme', assign it as new theme.
+    $theme = \Drupal::service('request_stack')->getCurrentRequest()->query->get('theme');
+    if (isset($theme)) {
+      // Manually validate the value.
+      // @todo Consider switching the form's method to GET.
+      $themes = Switchtheme::SwitchthemeOptions();
+      if (isset($themes[$theme])) {
+        $form_state = new FormState();
+        $values['theme'] = $theme;
+        $form_state->setValues($values);
+        \Drupal::formBuilder()->submitForm('Drupal\switchtheme\Form\SwitchthemeSwitchForm', $form_state);
+      }
+    }
+  }
+}
diff --git a/src/Form/SwitchthemeAdminSettings.php b/src/Form/SwitchthemeAdminSettings.php
new file mode 100644
index 0000000..cd9abde
--- /dev/null
+++ b/src/Form/SwitchthemeAdminSettings.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Form\SwitchthemeAdminSettings.
+ */
+
+namespace Drupal\switchtheme\Form;
+
+use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use Drupal\switchtheme\Switchtheme;
+
+/**
+ * Administration settings form.
+ */
+class SwitchthemeAdminSettings extends ConfigFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'switchtheme_admin';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $config = $this->config('switchtheme.settings');
+    $settings = $config->get();
+
+    $options = Switchtheme::SwitchthemeOptions();
+    foreach ($options as $name => $label) {
+      $form['switchtheme_' . $name] = array(
+        '#type' => 'textfield',
+        '#title' => $label,
+        '#default_value' =>  $settings['switchtheme_' . $name],
+      );
+    }
+
+
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $config = $this->config('switchtheme.settings');
+
+    foreach (Element::children($form) as $variable) {
+      $config->set($variable, $form_state->getValue($form[$variable]['#parents']));
+    }
+    $config->save();
+
+    if (method_exists($this, '_submitForm')) {
+      $this->_submitForm($form, $form_state);
+    }
+
+    parent::submitForm($form, $form_state);
+  }
+
+}
diff --git a/src/Form/SwitchthemeSwitchForm.php b/src/Form/SwitchthemeSwitchForm.php
new file mode 100644
index 0000000..d49f627
--- /dev/null
+++ b/src/Form/SwitchthemeSwitchForm.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Form\SwitchthemeSwitchForm.
+ */
+
+namespace Drupal\switchtheme\Form;
+
+use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use \Drupal\user\Entity\User;
+use Drupal\switchtheme\Switchtheme;
+
+/**
+ * Administration settings form.
+ */
+class SwitchthemeSwitchForm extends ConfigFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'switchtheme_switch_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    global $theme_key;
+
+    $options = Switchtheme::SwitchthemeSelect();
+    // Nothing to switch if there is only one theme.
+    if (count($options) < 2) {
+      $form['#access'] = FALSE;
+      return $form;
+    }
+
+    $form['widget'] = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('container-inline')),
+    );
+    $form['widget']['theme'] = array(
+      '#type' => 'select',
+      '#title' => t('Change the way this site looks'),
+      '#title_display' => 'attribute',
+      '#options' => $options,
+      '#required' => TRUE,
+    );
+    // Only if no custom theme could be determined, check whether we can preselect
+    // the current theme.
+    if (!isset($form['widget']['theme']['#default_value']) && isset($options[$theme_key])) {
+      $form['widget']['theme']['#default_value'] = $theme_key;
+    }
+
+    $form['widget']['actions'] = array('#type' => 'actions');
+    $form['widget']['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Switch'),
+      '#id' => 'switchtheme-submit',
+    );
+
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    parent::validateForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $user = \Drupal::currentUser();
+
+    // Save the setting for authenticated users, if the "select different theme"
+    // permission has been granted.
+    if ($user->id() > 0 && \Drupal::currentUser()->hasPermission('select different theme')) {
+      $account = User::load($user->id());
+      $account->theme = $form_state->getValue('theme');
+      $account->save();
+    }
+
+    // Otherwise save the setting in the user's session.
+    else if (\Drupal::currentUser()->hasPermission('switch theme')) {
+      $_SESSION['custom_theme'] = $form_state->getValue('theme');
+    }
+    parent::submitForm($form, $form_state);
+  }
+
+}
diff --git a/src/Plugin/Block/SwitchthemeBlock.php b/src/Plugin/Block/SwitchthemeBlock.php
new file mode 100644
index 0000000..0a121f8
--- /dev/null
+++ b/src/Plugin/Block/SwitchthemeBlock.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Plugin\Block\SwitchthemeBlock.
+ */
+
+namespace Drupal\switchtheme\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a Switchtheme form block.
+ *
+ * @Block(
+ *   id = "switch_form",
+ *   admin_label = @Translation("Switch theme"),
+ * )
+ */
+class SwitchthemeBlock extends BlockBase {
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function build() {
+    $content = '';
+
+		if (\Drupal::currentUser()->hasPermission('switch theme')) {
+      $content = \Drupal::formBuilder()->getForm('Drupal\switchtheme\Form\SwitchthemeSwitchForm');
+    }
+
+		return array(
+			'#children' => \Drupal::service('renderer')->render($content),
+		);
+	}
+}
diff --git a/src/Plugin/Block/SwitchthemeRandomBlock.php b/src/Plugin/Block/SwitchthemeRandomBlock.php
new file mode 100644
index 0000000..8b9d9c7
--- /dev/null
+++ b/src/Plugin/Block/SwitchthemeRandomBlock.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Plugin\Block\SwitchthemeRandomBlock.
+ */
+
+namespace Drupal\switchtheme\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+use Drupal\switchtheme\Switchtheme;
+
+/**
+ * Provides a Switchtheme Random block.
+ *
+ * @Block(
+ *   id = "switch_random",
+ *   admin_label = @Translation("Random theme"),
+ * )
+ */
+class SwitchthemeRandomBlock extends BlockBase {
+
+	/**
+	 * {@inheritdoc}
+	 */
+	public function build() {
+    $content = '';
+
+		if (\Drupal::currentUser()->hasPermission('switch theme')) {
+      $content = Switchtheme::SwitchthemeDisplayRandomBlock();
+    }
+
+		return array(
+			'#children' => \Drupal::service('renderer')->render($content),
+		);
+	}
+}
diff --git a/src/Switchtheme.php b/src/Switchtheme.php
new file mode 100644
index 0000000..2b6d9d1
--- /dev/null
+++ b/src/Switchtheme.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Switchtheme.
+ */
+
+namespace Drupal\switchtheme;
+
+use Drupal\Core\Url;
+
+class Switchtheme {
+
+  /**
+   * Returns an #options list of enabled themes.
+   */
+  public static function SwitchthemeOptions() {
+    $options = array();
+    $theme_handler = \Drupal::service('theme_handler');
+    $themes = $theme_handler->listInfo();
+    foreach ($themes as $theme_name => $theme) {
+      if (\Drupal::service('access_check.theme')->checkAccess($theme_name)) {
+        $options[$theme_name] = $theme->info['name'];
+      }
+    }
+    return $options;
+  }
+
+  /**
+   * Returns switchtheme_options() with customized theme labels.
+   */
+  public static function SwitchthemeSelect() {
+    $options = array();
+    foreach (Switchtheme::SwitchthemeOptions() as $name => $label) {
+      $options[$name] = \Drupal::config('switchtheme.settings')->get('switchtheme_' . $name);
+    }
+    asort($options);
+    return $options;
+  }
+
+  /**
+   * Renders a random theme with screenshot to switch to.
+   */
+  public static function SwitchthemeDisplayRandomBlock() {
+    $theme_handler = \Drupal::service('theme_handler');
+    $themes = $theme_handler->listInfo();
+    shuffle($themes);
+    foreach ($themes as $key => $theme) {
+      if ($theme->status && !empty($theme->info['screenshot'])) {
+        // Return the first theme with a screenshot.
+        $image = array(
+          '#theme' => 'image',
+          '#uri' => $theme->info['screenshot'],
+          '#alt' => t('Preview of @theme', array('@theme' => $theme->getName())),
+        );
+        $query = Url::fromRoute('<current>', [], ['absolute' => TRUE]);
+        $build['theme'] = array(
+          '#type' => 'link',
+          '#title' => \Drupal::service('renderer')->render($image),
+          '#url' => $query,
+          '#options' => array(
+            'query' => array(
+              'theme' => $theme->getName(),
+            ),
+            'html' => TRUE,
+          ),
+        );
+        return $build;
+      }
+    }
+  }
+}
diff --git a/src/Theme/SwitchthemeNegotiator.php b/src/Theme/SwitchthemeNegotiator.php
new file mode 100644
index 0000000..fc16db2
--- /dev/null
+++ b/src/Theme/SwitchthemeNegotiator.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\switchtheme\Theme\SwitchthemeNegotiator.
+ */
+
+namespace Drupal\switchtheme\Theme;
+
+use Drupal\Core\Theme;
+use Drupal\Core\Theme\ThemeNegotiatorInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\switchtheme\Switchtheme;
+use \Drupal\user\Entity\User;
+
+class SwitchthemeNegotiator implements ThemeNegotiatorInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(RouteMatchInterface $route_match) {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function determineActiveTheme(RouteMatchInterface $route_match) {
+    $account = \Drupal::currentUser();
+
+    $set_theme = '';
+
+    // The HTTP GET parameter 'theme' always has precedence.
+    $theme = \Drupal::service('request_stack')->getCurrentRequest()->query->get('theme');
+    $themes = Switchtheme::SwitchthemeOptions();
+
+    if (!empty($theme)) {
+      $set_theme = $theme;
+    }
+    // Check whether the user session contains a custom theme.
+    if (isset($_SESSION['custom_theme'])) {
+      $set_theme = $_SESSION['custom_theme'];
+    }
+    // Check whether the current user has a custom theme assigned.
+    $user = User::load($account->id());
+    if (!empty($user->theme)) {
+      $set_theme = $user->theme;
+    }
+
+    if (isset($themes[$set_theme])) {
+      return $set_theme;
+    }
+
+  }
+}
diff --git a/switchtheme.admin.inc b/switchtheme.admin.inc
deleted file mode 100644
index d052bf8..0000000
--- a/switchtheme.admin.inc
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-/**
- * @file
- * Administrative functionality for Switchtheme.
- */
-
-/**
- * Form constructor for theme settings.
- */
-function switchtheme_admin_settings($form, &$form_state) {
-  $options = switchtheme_options();
-  foreach ($options as $name => $label) {
-    $form['switchtheme']['switchtheme_' . $name] = array(
-      '#type' => 'textfield',
-      '#title' => $label,
-      '#default_value' => variable_get('switchtheme_' . $name, $label),
-    );
-  }
-  return system_settings_form($form);
-}
-
-/**
- * Form constructor for browser settings.
- */
-function switchtheme_admin_browser_settings($form, &$form_state) {
-  $form['switchtheme_browser_enabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Switch theme based on the browser of the visitor'),
-    '#default_value' => variable_get('switchtheme_browser_enabled', FALSE),
-  );
-
-  $themes = array('default' => t('Default'));
-  $themes += switchtheme_options();
-  $useragents = array();
-  $result = db_query('SELECT data FROM {browscap}')->fetchCol();
-  foreach ($result as $data) {
-    $data = unserialize($data);
-    if (isset($data['parent'])) {
-      $useragents[trim($data['parent'])][] = isset($data['platform']) ? $data['platform'] : '';
-    }
-  }
-  $form['switchtheme_browser'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Browsers'),
-    '#collapsible' => FALSE,
-    '#collapsed' => FALSE,
-  );
-  foreach ($useragents as $parent => $platforms) {
-    $form['switchtheme_browser']['switchtheme_browser_' . md5($parent)] = array(
-      '#type' => 'select',
-      '#title' => $parent,
-      '#options' => $themes,
-      '#default_value' => variable_get('switchtheme_browser_' . md5($parent), 'default'),
-    );
-  }
-  return system_settings_form($form);
-}
-
diff --git a/switchtheme.info b/switchtheme.info
deleted file mode 100644
index f70e4b3..0000000
--- a/switchtheme.info
+++ /dev/null
@@ -1,5 +0,0 @@
-name = Switchtheme
-description = Allows switching the theme in various means.
-core = 7.x
-package = User interface
-configure = admin/config/user-interface/switchtheme
diff --git a/switchtheme.info.yml b/switchtheme.info.yml
new file mode 100644
index 0000000..b39d8af
--- /dev/null
+++ b/switchtheme.info.yml
@@ -0,0 +1,8 @@
+name: Switchtheme
+description: 'Allows switching the theme in various means.'
+core: 8.x
+package: User interface
+configure: switchtheme.settings_form
+type: module
+
+
diff --git a/switchtheme.install b/switchtheme.install
deleted file mode 100644
index 02fd816..0000000
--- a/switchtheme.install
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-/**
- * @file
- * Installation functions for Switchtheme module.
- */
-
-/**
- * Implements hook_uninstall().
- */
-function switchtheme_uninstall() {
-  db_delete('variable')
-    ->condition('name', 'switchtheme_%', 'LIKE')
-    ->execute;
-}
diff --git a/switchtheme.module b/switchtheme.module
index 3248889..a3100a2 100644
--- a/switchtheme.module
+++ b/switchtheme.module
@@ -5,300 +5,24 @@
  * Adds a block with a user theme switcher.
  */
 
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
+
 /**
  * Implements hook_help().
  */
-function switchtheme_help($path, $arg) {
-  switch ($path) {
-    case 'admin/help#switchtheme':
+function switchtheme_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.switchtheme':
       $output = '';
       $output .= '<h3>' . t('About') . '</h3>';
       $output .= '<p>' . t('The Switchtheme module provides <a href="@blocks-url">blocks</a> to allow users to switch themes on the fly. You can define custom labels to display for each enabled theme. It also allows the theme to be changed based on the visitor browser (requires <a href="@browscap-url">Browscap</a> module).', array(
-        '@blocks-url' => url('admin/structure/block'),
+        '@blocks-url' => Url::fromRoute('block.admin_display'),
         '@browscap-url' => 'http://drupal.org/project/browscap',
       )) . '</p>';
       return $output;
 
-    case 'admin/config/user-interface/switchtheme':
-    case 'admin/config/user-interface/switchtheme/themes':
+    case 'switchtheme.settings_form':
       return t('Set a label for each enabled theme. This is what will be displayed to the user in the selection box.');
   }
 }
-
-/**
- * Implements hook_permission().
- */
-function switchtheme_permission() {
-  return array(
-    'administer switch' => array(
-      'title' => t('Administer SwitchTheme'),
-    ),
-    'switch theme' => array(
-      'title' => t('Switch themes'),
-    ),
-    'select different theme' => array(
-      'title' => t('Permanently use a custom theme'),
-    ),
-  );
-}
-
-/**
- * Implements hook_menu().
- */
-function switchtheme_menu() {
-  $items['admin/config/user-interface/switchtheme'] = array(
-    'title' => 'Switchtheme',
-    'description' => 'Configure theme selection settings.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('switchtheme_admin_settings'),
-    'access arguments' => array('administer switch'),
-    'file' => 'switchtheme.admin.inc',
-  );
-  $items['admin/config/user-interface/switchtheme/themes'] = array(
-    'title' => 'Themes',
-    'description' => 'Configure theme selection options of the Switchtheme block.',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
-  );
-  if (module_exists('browscap')) {
-    $items['admin/config/user-interface/switchtheme/browser'] = array(
-      'title' => 'Browsers',
-      'description' => 'Configure automatic theme selection for visitors.',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('switchtheme_admin_browser_settings'),
-      'access arguments' => array('administer switch'),
-      'file' => 'switchtheme.admin.inc',
-      'type' => MENU_LOCAL_TASK,
-      'weight' => 2,
-    );
-  }
-  return $items;
-}
-
-/**
- * Implements hook_init().
- */
-function switchtheme_init() {
-  // Skip maintenance mode and maintenance pages.
-  // @see menu_get_custom_theme()
-  if (_menu_site_is_offline(TRUE) || defined('MAINTENANCE_MODE')) {
-    return;
-  }
-
-  // If there is a HTTP GET parameter 'theme', assign it as new theme.
-  if (isset($_GET['theme'])) {
-    // Manually validate the value.
-    // @todo Consider switching the form's method to GET.
-    $themes = switchtheme_options();
-    if (isset($themes[$_GET['theme']])) {
-      $form = array();
-      $form_state['values']['theme'] = $_GET['theme'];
-      switchtheme_switch_form_submit($form, $form_state);
-    }
-  }
-}
-
-/**
- * Implements hook_custom_theme().
- *
- * @param $return_single
- *   Boolean whether to return the first determined custom theme (TRUE) or all
- *   determined values (FALSE). Defaults to TRUE.
- */
-function switchtheme_custom_theme($return_single = TRUE) {
-  global $user;
-
-  $custom_theme = array();
-
-  // The HTTP GET parameter 'theme' always has precedence.
-  if (isset($_GET['theme'])) {
-    $custom_theme['get'] = $_GET['theme'];
-  }
-  // Check whether the user session contains a custom theme.
-  if (isset($_SESSION['custom_theme'])) {
-    $custom_theme['session'] = $_SESSION['custom_theme'];
-  }
-  // Check whether the current user has a custom theme assigned.
-  if (!empty($user->theme)) {
-    $custom_theme['user'] = $user->theme;
-  }
-  // Lastly, check whether a theme can be automatically selected.
-  if (module_exists('browscap') && variable_get('switchtheme_browser_enabled', FALSE)) {
-    $browser = browscap_get_browser();
-    if (isset($browser['parent'])) {
-      $parent = trim($browser['parent']);
-      $browser_theme = variable_get('switchtheme_browser_' . md5($parent), 'default');
-      if ($browser_theme != 'default') {
-        $custom_theme['browser'] = $browser_theme;
-      }
-    }
-  }
-
-  if ($return_single) {
-    // reset() would return FALSE if $custom_theme is empty.
-    return (!empty($custom_theme) ? reset($custom_theme) : NULL);
-  }
-  return $custom_theme;
-}
-
-/**
- * Implements hook_block_info()
- */
-function switchtheme_block_info() {
-  $blocks['switch_form'] = array(
-    'info' => t('Switch theme'),
-    'cache' => DRUPAL_NO_CACHE,
-  );
-  $blocks['switch_random'] = array(
-    'info' => t('Random theme'),
-    'cache' => DRUPAL_NO_CACHE,
-  );
-  return $blocks;
-}
-
-/**
- * Implements hook_block_view()
- */
-function switchtheme_block_view($delta = '') {
-  if (user_access('switch theme')) {
-    switch ($delta) {
-      case 'switch_form':
-        $block['subject'] = t('Theme');
-        $block['content'] = drupal_get_form('switchtheme_switch_form');
-        return $block;
-
-      case 'switch_random':
-        $block['subject'] = t('Random theme');
-        $block['content'] = switchtheme_display_random_block();
-        return $block;
-    }
-  }
-}
-
-/**
- * Renders a random theme with screenshot to switch to.
- */
-function switchtheme_display_random_block() {
-  $themes = list_themes();
-  shuffle($themes);
-  foreach ($themes as $key => $theme) {
-    if ($theme->status && !empty($theme->info['screenshot'])) {
-      // Return the first theme with a screenshot.
-      $build['theme'] = array(
-        '#type' => 'link',
-        '#title' => theme('image', array(
-          'path' => $theme->info['screenshot'],
-          'alt' => t('Preview of @theme', array('@theme' => $theme->name)),
-        )),
-        '#href' => $_GET['q'],
-        '#options' => array(
-          'query' => array(
-            'theme' => $theme->name,
-          ),
-          'html' => TRUE,
-        ),
-      );
-      return $build;
-    }
-  }
-}
-
-/**
- * Form constructor for theme switcher form.
- */
-function switchtheme_switch_form($form, &$form_state) {
-  global $user, $theme_key;
-
-  $options = switchtheme_select();
-  // Nothing to switch if there is only one theme.
-  if (count($options) < 2) {
-    $form['#access'] = FALSE;
-    return $form;
-  }
-
-  $form['widget'] = array(
-    '#type' => 'container',
-    '#attributes' => array('class' => array('container-inline')),
-  );
-  $form['widget']['theme'] = array(
-    '#type' => 'select',
-    '#title' => t('Change the way this site looks'),
-    '#title_display' => 'attribute',
-    '#options' => $options,
-    '#required' => TRUE,
-  );
-  // The current page may be displayed in a theme that is not available to
-  // Switchtheme (e.g., a disabled admin theme). And even if the current theme
-  // is available to Switchtheme, it might not be the theme the current user
-  // previously selected. So in order to not confuse the user, we need to figure
-  // out the proper, last set theme for the #default_value.
-  foreach (switchtheme_custom_theme(FALSE) as $name) {
-    if (isset($options[$name])) {
-      $form['widget']['theme']['#default_value'] = $name;
-      break;
-    }
-  }
-  // Only if no custom theme could be determined, check whether we can preselect
-  // the current theme.
-  if (!isset($form['widget']['theme']['#default_value']) && isset($options[$theme_key])) {
-    $form['widget']['theme']['#default_value'] = $theme_key;
-  }
-
-  $form['widget']['actions'] = array('#type' => 'actions');
-  $form['widget']['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Switch'),
-    '#id' => 'switchtheme-submit',
-  );
-  return $form;
-}
-
-/**
- * Form submission handler for switchtheme_switch_form().
- *
- * We do not validate the input here, because that is done in init_theme()
- * already.
- */
-function switchtheme_switch_form_submit($form, &$form_state) {
-  global $user;
-
-  // Save the setting for authenticated users, if the "select different theme"
-  // permission has been granted.
-  if ($user->uid > 0 && user_access('select different theme')) {
-    $account = user_load($user->uid);
-    user_save($account, array(
-      'theme' => $form_state['values']['theme'],
-    ));
-  }
-  // Otherwise save the setting in the user's session.
-  elseif (user_access('switch theme')) {
-    $_SESSION['custom_theme'] = $form_state['values']['theme'];
-  }
-}
-
-/**
- * Returns an #options list of enabled themes.
- */
-function switchtheme_options() {
-  $options = array();
-  $themes = list_themes();
-  foreach ($themes as $name => $theme) {
-    if ($theme->status) {
-      $options[$name] = $theme->info['name'];
-    }
-  }
-  return $options;
-}
-
-/**
- * Returns switchtheme_options() with customized theme labels.
- */
-function switchtheme_select() {
-  $options = array();
-  foreach (switchtheme_options() as $name => $label) {
-    $options[$name] = variable_get('switchtheme_' . $name, $label);
-  }
-  asort($options);
-  return $options;
-}
-
diff --git a/switchtheme.permissions.yml b/switchtheme.permissions.yml
new file mode 100644
index 0000000..3e947d1
--- /dev/null
+++ b/switchtheme.permissions.yml
@@ -0,0 +1,6 @@
+administer switch:
+  title: 'Administer SwitchTheme'
+switch theme:
+  title: 'Switch themes'
+select different theme:
+  title: 'Permanently use a custom theme'
\ No newline at end of file
diff --git a/switchtheme.routing.yml b/switchtheme.routing.yml
new file mode 100644
index 0000000..d8f4199
--- /dev/null
+++ b/switchtheme.routing.yml
@@ -0,0 +1,8 @@
+switchtheme.settings_form:
+  path: /admin/config/user-interface/switchtheme
+  defaults:
+    _title: Switchtheme
+    _form: \Drupal\switchtheme\Form\SwitchthemeAdminSettings
+    _description: Configure theme selection settings.
+  requirements:
+    _permission: 'administer switch'
diff --git a/switchtheme.services.yml b/switchtheme.services.yml
new file mode 100644
index 0000000..c6b8afa
--- /dev/null
+++ b/switchtheme.services.yml
@@ -0,0 +1,10 @@
+services:
+  theme.negotiator.switchtheme:
+    class: Drupal\switchtheme\Theme\SwitchthemeNegotiator
+    tags:
+      - { name: theme_negotiator, priority: 0 }
+  init_subscriber:
+      class: Drupal\switchtheme\EventSubscriber\InitSubscriber
+      tags:
+        -
+          name: event_subscriber
\ No newline at end of file
