icon-banner 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9efce0274be7532b108c0374f84021b8f5fed3d
4
+ data.tar.gz: 2dcc37968b8978d58989627daa69a69899156dbc
5
+ SHA512:
6
+ metadata.gz: 452fa34575ab520f92d453d0740767cbda45152de535e5fc1bb2a7a23e3bd19811bbd40383b7f415c5d63e81d221ccc25c30a2975458180f3e76f95483601088
7
+ data.tar.gz: 56234725fd3f474b8ad7c0edd48e454b77cfd2a0051026e5a789afe134b732dc85d5df11f93b55af4c9ea1e61f36fa81a2a344c284de746ad4ba5d611c3d8715
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Émile Bélair
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ <h3 align="center">
2
+ <a href="https://github.com/ebelair/icon-banner/blob/master/.assets/icon_banner.png">
3
+ <img src="https://github.com/ebelair/icon-banner/blob/master/.assets/icon_banner.png?raw=true" alt="IconBanner" width="400">
4
+ </a>
5
+ </h3>
6
+
7
+ [![GitHub: @ebelair](https://img.shields.io/badge/author-@ebelair-blue.svg?style=flat)](https://github.com/ebelair)
8
+ [![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/fastlane/fastlane/blob/master/LICENSE)
9
+ [![Gem](https://img.shields.io/gem/v/icon-banner.svg?style=flat)](https://rubygems.org/gems/icon-banner)
10
+ [![Fastlane](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-icon_banner)
11
+
12
+ **IconBanner** adds custom nice-looking banners over your mobile app icons.
13
+
14
+ It is available both as a **command-line tool** and as a **Fastlane plugin**.
15
+
16
+ > Currently **iOS-only**, but Android is in the works.
17
+
18
+ ## Introduction
19
+
20
+ **IconBanner** is inspired by the great [HazAT/badge](https://github.com/HazAT/badge). It provides custom banner creation on-the-fly, allowing to create different text banners for different build contexts.
21
+
22
+ It allows to create these kind of icons:
23
+
24
+ |Original|Daily|QA|Staging|Production|
25
+ |---|---|---|---|---|
26
+ |![FaceTime Regular](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.appiconset/facetime.png)|![FaceTime Daily](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/facetime_Daily.png)|![FaceTime QA](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/facetime_QA.png)|![FaceTime Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/facetime_Staging.png)|![FaceTime Production](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/facetime_Production.png)|
27
+ |![iBooks Regular](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.appiconset/ibooks.png)|![iBooks Daily](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/ibooks_Daily.png)|![iBooks QA](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/ibooks_QA.png)|![iBooks Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/ibooks_Staging.png)|![iBooks Production](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/ibooks_Production.png)|
28
+ |![Podcasts Regular](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.appiconset/podcasts.png)|![Podcasts Daily](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/podcasts_Daily.png)|![Podcasts QA](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/podcasts_QA.png)|![Podcasts Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/podcasts_Staging.png)|![Podcasts Production](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/podcasts_Production.png)|
29
+ |![TestFlight Regular](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.appiconset/testflight.png)|![TestFlight Daily](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/testflight_Daily.png)|![TestFlight QA](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/testflight_QA.png)|![TestFlight Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/testflight_Staging.png)|![TestFlight Production](https://github.com/ebelair/icon-banner/raw/master/spec/Reference/testflight_Production.png)|
30
+
31
+ ## Setup
32
+
33
+ ### 🚀 Fastlane
34
+
35
+ Start by running this command in your project repository:
36
+
37
+ ```bash
38
+ fastlane add_plugin fastlane-plugin-icon_banner
39
+ ```
40
+
41
+ Then simply add the following actions in your Fastfile:
42
+
43
+ ```ruby
44
+ lane :sample do
45
+ icon_banner([options])
46
+ # [build_ios_app and other actions]
47
+ icon_banner_restore()
48
+ end
49
+ ```
50
+
51
+ For more details, see the [Usage](https://github.com/ebelair/icon-banner#options) section below.
52
+
53
+ ### 💻 Standalone
54
+
55
+ First install the gem:
56
+
57
+ ```bash
58
+ gem install icon-banner
59
+ ```
60
+
61
+ Then use it directly:
62
+
63
+ ```bash
64
+ icon-banner generate [options]
65
+ icon-banner restore
66
+ ```
67
+
68
+ For more details, see the [Usage](https://github.com/ebelair/icon-banner#options) section below.
69
+
70
+ ## Usage
71
+
72
+ ### Generate
73
+
74
+ Generates banners and adds them to app icons. Available via:
75
+
76
+ - The `icon_banner()` Fastlane action
77
+ - The `icon-banner generate` terminal command
78
+
79
+ | Key | Description | Default |
80
+ |--------|------------------------------------|---------|
81
+ | label | Sets the text to display inside the banner | BETA |
82
+ | color | Sets the text color (when not set, the script uses the dominant icon color) | |
83
+ | font | Sets the text font with a _direct link_ to a TTF file (when not set, the script uses the embedded LilitaOne font) | |
84
+ | backup | Creates a backup of icons before applying banners (only set to `false` if you are under source-control) | true |
85
+
86
+ Sample usages:
87
+
88
+ ```ruby
89
+ # fastlane
90
+ icon_banner(label: 'QA')
91
+ icon_banner(label: 'QA', color: '#ff000088', font: '/Users/johndoe/Documents/mybestfont.ttf')
92
+ ```
93
+
94
+ ```bash
95
+ # command-line
96
+ icon-banner generate --label QA
97
+ icon-banner generate --label QA --color '#ff000088' --font '/Users/johndoe/Documents/mybestfont.ttf'
98
+ ```
99
+
100
+ ### Restore
101
+
102
+ Restores app icons without banners (if backups are available). Available via:
103
+
104
+ - The `icon_banner_restore()` Fastlane action
105
+ - The `icon-banner restore` terminal command
106
+
107
+ No options are required – if backup files are available, they are automatically restored.
108
+
109
+ Sample usage:
110
+
111
+ ```ruby
112
+ # fastlane
113
+ icon_banner_restore()
114
+ ```
115
+
116
+ ```bash
117
+ # command-line
118
+ icon-banner restore
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ebelair/icon-banner.
124
+
125
+ ## License
126
+
127
+ IconBanner is ©2019 [ebelair](https://github.com/ebelair) and may be freely distributed under the [MIT license](https://opensource.org/licenses/MIT). See the [`LICENSE`](https://github.com/ebelair/icon-banner/blob/master/LICENSE.md) file.
128
+
129
+ The project is highly inspired by [`badge` by HazAT](https://github.com/HazAT/badge). Used also under the [MIT license](https://opensource.org/licenses/MIT). Thanks again. 🙏
130
+
131
+ ## About ebelair
132
+
133
+ [Émile Bélair](https://github.com/ebelair) acts as a Product Owner @ [Mirego](https://www.mirego.com). He enjoys creating great products and works hard with his team to deliver some of the greatest.
Binary file
data/bin/icon-banner ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'icon_banner'
5
+
6
+ IconBanner::IconBanner.start
@@ -0,0 +1,96 @@
1
+ require 'icon_banner/appiconset'
2
+ require 'commander'
3
+
4
+ module IconBanner
5
+ VERSION = '0.1.0'
6
+ DESCRIPTION = 'IconBanner adds custom nice-looking banners over your mobile app icons'
7
+
8
+ UI = FastlaneCore::UI
9
+
10
+ class IconBanner
11
+ include Commander::Methods
12
+
13
+ def self.start
14
+ self.new.run
15
+ end
16
+
17
+ def run
18
+ program :name, 'IconBanner'
19
+ program :version, VERSION
20
+ program :description, DESCRIPTION
21
+
22
+ global_option('--verbose', 'Shows a more verbose output') { FastlaneCore::Globals.verbose = true }
23
+
24
+ command :generate do |c|
25
+ c.syntax = 'icon-banner generate [path] [options]'
26
+ c.description = 'Generates banners and adds them to app icons'
27
+ FastlaneCore::CommanderGenerator.new.generate(IconBanner::available_options, command: c)
28
+
29
+ c.action do |args, options|
30
+ path = args[0] || '.'
31
+ options = FastlaneCore::Configuration.create(IconBanner::available_options, options.__hash__)
32
+ IconBanner.generate(path, options)
33
+ end
34
+ end
35
+
36
+ command :restore do |c|
37
+ c.syntax = 'icon-banner restore [path]'
38
+ c.description = 'Restores app icons without banners (if backups are available)'
39
+
40
+ c.action do |args|
41
+ path = args[0] || '.'
42
+ IconBanner.restore(path)
43
+ end
44
+ end
45
+
46
+ run!
47
+ end
48
+
49
+ def self.generate(path, options)
50
+ AppIconSet.new.generate(path, options)
51
+ end
52
+
53
+ def self.restore(path)
54
+ AppIconSet.new.restore(path)
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(key: :label,
60
+ description: 'Sets the text to display inside the banner',
61
+ default_value: 'BETA',
62
+ optional: true),
63
+
64
+ FastlaneCore::ConfigItem.new(key: :color,
65
+ description: 'Sets the text color (when not set, the script uses the dominant icon color)',
66
+ optional: true),
67
+
68
+ FastlaneCore::ConfigItem.new(key: :font,
69
+ description: 'Sets the text font with a _direct link_ to a TTF file (when not set, the script uses the embedded LilitaOne font)',
70
+ optional: true),
71
+
72
+ FastlaneCore::ConfigItem.new(key: :backup,
73
+ description: 'Creates a backup of icons before applying banners (only set to `false` if you are under source-control)',
74
+ is_string: false,
75
+ default_value: true,
76
+ optional: true)
77
+ ]
78
+ end
79
+
80
+ def self.validate_libs!
81
+ begin
82
+ UI.error('ImageMagick was not found on your system. To install it, run the following command:')
83
+ UI.command('brew install imagemagick')
84
+ UI.user_error!('IconBanner is missing requirements.')
85
+ end unless `which convert`.include?('convert')
86
+ end
87
+
88
+ def self.base_path
89
+ File.dirname __dir__ + '/../../'
90
+ end
91
+
92
+ def self.font_path
93
+ File.join base_path, 'assets', 'LilitaOne.ttf'
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,132 @@
1
+ require 'fastlane_core'
2
+ require 'mini_magick'
3
+
4
+ module IconBanner
5
+ class AppIconSet
6
+ BASE_ICON_PATH = '/**/*.appiconset/*.{png,PNG}'
7
+ BACKUP_EXTENSION = '.bak'
8
+
9
+ def generate(path, options)
10
+ IconBanner.validate_libs!
11
+
12
+ restore(path) # restore in case it was already run before
13
+
14
+ app_icons = get_app_icons(path)
15
+
16
+ label = options[:label]
17
+ font = options[:font] || IconBanner.font_path
18
+
19
+ if app_icons.count > 0
20
+ UI.message 'Starting banner process...'
21
+
22
+ app_icons.each do |icon_path|
23
+ UI.verbose "Processing #{icon_path}"
24
+ create_backup icon_path if options[:backup]
25
+
26
+ color = options[:color]
27
+ begin
28
+ color = find_base_color(icon_path)
29
+ UI.verbose "Color: #{color}"
30
+ end unless color
31
+
32
+ banner_file = Tempfile.new %w[banner .png]
33
+ generate_banner banner_file.path, color, label, font
34
+ process_icon icon_path, banner_file.path
35
+ banner_file.close
36
+
37
+ UI.verbose "Completed processing #{File.basename icon_path}"
38
+ UI.verbose ''
39
+ end
40
+
41
+ UI.message 'Completed banner process.'
42
+ else
43
+ UI.error('No icon found.')
44
+ end
45
+ end
46
+
47
+ def restore(path)
48
+ app_icons = get_app_icons(path)
49
+
50
+ if app_icons.count > 0
51
+ UI.message 'Starting restore...'
52
+
53
+ app_icons.each do |icon_path|
54
+ UI.verbose "Restoring #{icon_path}"
55
+ restore_backup icon_path
56
+ end
57
+
58
+ UI.message 'Completed restore.'
59
+ end
60
+ end
61
+
62
+ def get_app_icons(path)
63
+ app_icons = Dir.glob("#{path}#{BASE_ICON_PATH}")
64
+ app_icons.reject { |i| i[/\/Carthage\//] || i[/\/Pods\//] ||i[/\/Releases\//] }
65
+ end
66
+
67
+ def find_base_color(path)
68
+ color = MiniMagick::Tool::Convert.new do |convert|
69
+ convert << path
70
+ convert.colors 3
71
+ convert << '-unique-colors'
72
+ convert.format '%[pixel:u]'
73
+ convert << 'xc:transparent'
74
+ convert << 'info:-'
75
+ end
76
+ color[/rgba?\([^)]*\)/]
77
+ end
78
+
79
+ def generate_banner(path, color, label, font)
80
+ MiniMagick::Tool::Convert.new do |convert|
81
+ convert.size '1024x1024'
82
+ convert << 'xc:transparent'
83
+ convert << path
84
+ end
85
+
86
+ banner = MiniMagick::Image.new path
87
+
88
+ banner.combine_options do |combine|
89
+ combine.fill 'rgba(0,0,0,0.25)'
90
+ combine.draw 'polygon 0,306 0,590 590,0 306,0'
91
+ combine.blur '0x10'
92
+ end
93
+
94
+ banner.combine_options do |combine|
95
+ combine.fill 'white'
96
+ combine.draw 'polygon 0,306 0,590 590,0 306,0'
97
+ end
98
+
99
+ banner.combine_options do |combine|
100
+ combine.font font
101
+ combine.fill color
102
+ combine.gravity 'Center'
103
+ combine.pointsize 150 - ([label.length - 8, 0].max * 8)
104
+ combine.draw "affine 0.5,-0.5,0.5,0.5,-286,-286 text 0,0 \"#{label}\""
105
+ end
106
+ end
107
+
108
+ def process_icon(icon_path, banner_path)
109
+ icon = MiniMagick::Image.open(icon_path)
110
+ banner = MiniMagick::Image.open(banner_path)
111
+ banner.resize "#{icon.width}x#{icon.height}"
112
+ icon.composite(banner).write(icon_path)
113
+ end
114
+
115
+ def create_backup(icon_path)
116
+ FileUtils.cp(icon_path, backup_path(icon_path))
117
+ end
118
+
119
+ def restore_backup(icon_path)
120
+ restore_path = backup_path(icon_path)
121
+ if File.exists?(restore_path)
122
+ FileUtils.cp(restore_path, icon_path)
123
+ File.delete restore_path
124
+ end
125
+ end
126
+
127
+ def backup_path(path)
128
+ ext = File.extname path
129
+ path.gsub(ext, BACKUP_EXTENSION + ext)
130
+ end
131
+ end
132
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: icon-banner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Émile Bélair
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fastlane
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.100'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.100'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mini_magick
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ description: IconBanner adds custom nice-looking banners over your mobile app icons
56
+ email:
57
+ - ebelair@me.com
58
+ executables:
59
+ - icon-banner
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE
64
+ - README.md
65
+ - assets/LilitaOne.ttf
66
+ - bin/icon-banner
67
+ - lib/icon_banner.rb
68
+ - lib/icon_banner/appiconset.rb
69
+ homepage: https://github.com/ebelair/icon-banner
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.6.11
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Banners for your app icons
93
+ test_files: []