{"id":17690220,"url":"https://github.com/onmyway133/easytheme","last_synced_at":"2025-05-05T22:15:49.642Z","repository":{"id":56924207,"uuid":"93325559","full_name":"onmyway133/EasyTheme","owner":"onmyway133","description":"👕👚 Theme management in Swift","archived":false,"fork":false,"pushed_at":"2020-09-30T09:30:56.000Z","size":34318,"stargazers_count":244,"open_issues_count":4,"forks_count":19,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-05T22:15:42.542Z","etag":null,"topics":["ios","macos","mode","night","skin","swift","theme"],"latest_commit_sha":null,"homepage":"https://onmyway133.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onmyway133.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-04T16:14:34.000Z","updated_at":"2025-04-17T00:47:21.000Z","dependencies_parsed_at":"2022-08-20T22:20:15.667Z","dependency_job_id":null,"html_url":"https://github.com/onmyway133/EasyTheme","commit_stats":null,"previous_names":["onmyway133/themes"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FEasyTheme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FEasyTheme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FEasyTheme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FEasyTheme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onmyway133","download_url":"https://codeload.github.com/onmyway133/EasyTheme/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252584333,"owners_count":21771945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","macos","mode","night","skin","swift","theme"],"created_at":"2024-10-24T11:50:14.009Z","updated_at":"2025-05-05T22:15:49.620Z","avatar_url":"https://github.com/onmyway133.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Themes\n\n[![CI Status](http://img.shields.io/travis/onmyway133/Themes.svg?style=flat)](https://travis-ci.org/onmyway133/Themes)\n[![Version](https://img.shields.io/cocoapods/v/Themes.svg?style=flat)](http://cocoadocs.org/docsets/Themes)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![License](https://img.shields.io/cocoapods/l/Themes.svg?style=flat)](http://cocoadocs.org/docsets/Themes)\n[![Platform](https://img.shields.io/cocoapods/p/Themes.svg?style=flat)](http://cocoadocs.org/docsets/Themes)\n![Swift](https://img.shields.io/badge/%20in-swift%203.0-orange.svg)\n\n![](Screenshots/Banner.png)\n\n\n\u003cdiv align = \"center\"\u003e\n\u003cimg src=\"Screenshots/demo.gif\" width=\"\" height=\"400\" /\u003e\n\u003cimg src=\"Screenshots/weather.gif\" width=\"\" height=\"400\" /\u003e\n\u003c/div\u003e\n\n## Story\n\nEver want to support Night mode? Or skin the app differently depending on the seasons? Or toggle features according to paid status? Well, those are actually reactions to app events.\n\nMany other frameworks encourage you to use hard coded values, like `label.xyz_textColors = [.red, .blue], textField.xyz_fonts = [font1, font2], ...`. This also makes it very hard to change because the usage of index, you need to remember that the 1st index is this theme, the 2nd index is that theme, ... Also, `xyz_textColors` is like trying to replicate the entire `UIKit` APIs, which updates often :scream:\n\n**Themes** is here to help. Usually, you have a finite number of colors and fonts in an app. You can have many more but that is not encourage and has design smells. When you have a theme, changing happens in one place. \n\n## Features\n\n- [x] Universal support for iOS, macOS, tvOS, watchOS\n- [x] Complete control over themes\n- [X] Update existing views\n- [x] Protocol oriented\n- [x] Extensible\n\n## Usage\n\n### Step 1: Create a theme\n\nDeclare your theme by conforming to `Theme`, which is just a marker protocol. You can declare whatever you like, including nested objects, all depending on your need. You can also create as many themes as you like\n\n```swift\nstruct MyTheme: Theme {\n  let topImage: UIImage\n  let cellColor: UIColor\n  let backgroundColor: UIColor\n  let name: String\n  let titleFont: UIFont\n  let subtitleFont: UIFont\n}\n```\n\nThen create some themes based on your templates\n\n```swift\nlet dayTheme = MyTheme(topImage: UIImage(named: \"day\"), cellColor: .white)\nlet nightTheme = MyTheme(topImage: UIImage(named: \"night\"), cellColor: .black)\n```\n\nThe beauty of this is that you can `init` your theme from json, which can be fetched from backend :rocket:\n\n```swift\nlet json = [\n  \"primary_color\": \"#21ABE9\",\n  \"font_name\": \"Chewy\"\n]\nlet unicornTheme = MyTheme(json)\n```\n\n### Step 2: Register your current theme\n\nWhen app launches, you need to declare 1 theme as the current, it can be loaded from cache\n\n```swift\nThemeManager.shared.currentTheme = dayTheme\n```\n\n### Step 3: React to theme change\n\nYou can do this wherever you like. It is set using the current theme, and whenever theme changes\n\n```swift\n// ViewController.swift\noverride func viewDidLoad() {\n  super.viewDidLoad()\n\n  use(MyTheme.self) {\n    $0.title = $1.name\n    $0.tableView.backgroundColor = $1.backgroundColor\n    $0.navigationController?.navigationBar.setBackgroundImage($1.topImage, for: .default)\n    $0.tableView.rowHeight = $1.name == \"Unicorn\" ? 180 : 120\n    $0.tableView.reloadData()\n  }\n}\n\n// Cell.swift\noverride func awakeFromNib() {\n  super.awakeFromNib()\n\n  imageView.layer.cornerRadius = 5\n  imageView.layer.masksToBounds = true\n\n  use(MyTheme.self) {\n    $0.titleLabel.font = $1.titleFont\n    $0.subtitleLabel.font = $1.subtitleFont\n    $0.container.backgroundColor = $1.cellColor\n  }\n}\n\n```\n\n### Step 4: Change the theme\n\nChange the current theme is as easy as assigning a new theme. All happens in real time and very fast\n\n```swift\nThemeManager.shared.currentTheme = nightTheme\n```\n\n## Installation\n\n**Themes** is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'Themes'\n```\n\n**Themes** is also available through [Carthage](https://github.com/Carthage/Carthage).\nTo install just write into your Cartfile:\n\n```ruby\ngithub \"onmyway133/Themes\"\n```\n\n**Themes** can also be installed manually. Just download and drop `Sources` folders in your project.\n\n## Author\n\nKhoa Pham, onmyway133@gmail.com\n\n## Contributing\n\nWe would love you to contribute to **Themes**, check the [CONTRIBUTING](https://github.com/onmyway133/Themes/blob/master/CONTRIBUTING.md) file for more info.\n\n## License\n\n**Themes** is available under the MIT license. See the [LICENSE](https://github.com/onmyway133/Themes/blob/master/LICENSE.md) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonmyway133%2Feasytheme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonmyway133%2Feasytheme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonmyway133%2Feasytheme/lists"}