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 +7 -0
- data/LICENSE +21 -0
- data/README.md +133 -0
- data/assets/LilitaOne.ttf +0 -0
- data/bin/icon-banner +6 -0
- data/lib/icon_banner.rb +96 -0
- data/lib/icon_banner/appiconset.rb +132 -0
- metadata +93 -0
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
|
+
[](https://github.com/ebelair)
|
8
|
+
[](https://github.com/fastlane/fastlane/blob/master/LICENSE)
|
9
|
+
[](https://rubygems.org/gems/icon-banner)
|
10
|
+
[](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
|
+
||||||
|
27
|
+
||||||
|
28
|
+
||||||
|
29
|
+
||||||
|
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
data/lib/icon_banner.rb
ADDED
@@ -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: []
|