icon-banner 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9efce0274be7532b108c0374f84021b8f5fed3d
4
- data.tar.gz: 2dcc37968b8978d58989627daa69a69899156dbc
3
+ metadata.gz: 77a0db864ce24768bed2ea3922bcd9b663ae016b
4
+ data.tar.gz: b6ae889f7b0e5b270046a8ed9a74725c1a8ad584
5
5
  SHA512:
6
- metadata.gz: 452fa34575ab520f92d453d0740767cbda45152de535e5fc1bb2a7a23e3bd19811bbd40383b7f415c5d63e81d221ccc25c30a2975458180f3e76f95483601088
7
- data.tar.gz: 56234725fd3f474b8ad7c0edd48e454b77cfd2a0051026e5a789afe134b732dc85d5df11f93b55af4c9ea1e61f36fa81a2a344c284de746ad4ba5d611c3d8715
6
+ metadata.gz: ce341e6efcce3f1487415c18391aecbc5eac6c48f0f28250f39cdb57bf0062160a7419ec2f9b6363ab6a675c55fadd15b23d44cb8eb4b9939821b9d0cd996961
7
+ data.tar.gz: 57a2f335650809cf1a80a539952dee4fafbed898d4fc2adb71dc4997370365e94634c6ae4c00fee8df069a5405a420aaf3f3acb3a42d2319c01a7de8870a98ee
data/README.md CHANGED
@@ -13,20 +13,29 @@
13
13
 
14
14
  It is available both as a **command-line tool** and as a **Fastlane plugin**.
15
15
 
16
- > Currently **iOS-only**, but Android is in the works.
17
-
18
16
  ## Introduction
19
17
 
20
18
  **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
19
 
22
- It allows to create these kind of icons:
20
+ It allows to create this kind of icons:
21
+
22
+ ### 🍏 iOS
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/Sample.reference/facetime_Daily.png)|![FaceTime QA](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/facetime_QA.png)|![FaceTime Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/facetime_Staging.png)|![FaceTime Production](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.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/Sample.reference/ibooks_Daily.png)|![iBooks QA](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/ibooks_QA.png)|![iBooks Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/ibooks_Staging.png)|![iBooks Production](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.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/Sample.reference/podcasts_Daily.png)|![Podcasts QA](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/podcasts_QA.png)|![Podcasts Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/podcasts_Staging.png)|![Podcasts Production](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.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/Sample.reference/testflight_Daily.png)|![TestFlight QA](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/testflight_QA.png)|![TestFlight Staging](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/testflight_Staging.png)|![TestFlight Production](https://github.com/ebelair/icon-banner/raw/master/spec/Sample.reference/testflight_Production.png)|
30
+
31
+ ### 🤖 Android
23
32
 
24
33
  |Original|Daily|QA|Staging|Production|
25
34
  |---|---|---|---|---|
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)|
35
+ |![Calender Regular](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_icons/calendar/ic_launcher.png)|![Calender Daily](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/calendar/ic_launcher_Daily.png)|![Calender QA](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/calendar/ic_launcher_QA.png)|![Calender Staging](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/calendar/ic_launcher_Staging.png)|![Calender Production](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/calendar/ic_launcher_Production.png)|
36
+ |![Games Regular](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_icons/games/ic_launcher.png)|![Games Daily](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/games/ic_launcher_Daily.png)|![Games QA](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/games/ic_launcher_QA.png)|![Games Staging](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/games/ic_launcher_Staging.png)|![Games Production](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/games/ic_launcher_Production.png)|
37
+ |![Mail Regular](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_icons/mail/ic_launcher.png)|![Mail Daily](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/mail/ic_launcher_Daily.png)|![Mail QA](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/mail/ic_launcher_QA.png)|![Mail Staging](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/mail/ic_launcher_Staging.png)|![Mail Production](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/mail/ic_launcher_Production.png)|
38
+ |![Movies Regular](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_icons/movies/ic_launcher.png)|![Movies Daily](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/movies/ic_launcher_Daily.png)|![Movies QA](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/movies/ic_launcher_QA.png)|![Movies Staging](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/movies/ic_launcher_Staging.png)|![Movies Production](https://github.com/ebelair/icon-banner/raw/master/spec/ic_launcher_reference/movies/ic_launcher_Production.png)|
30
39
 
31
40
  ## Setup
32
41
 
@@ -35,7 +44,7 @@ It allows to create these kind of icons:
35
44
  Start by running this command in your project repository:
36
45
 
37
46
  ```bash
38
- fastlane add_plugin fastlane-plugin-icon_banner
47
+ fastlane add_plugin icon_banner
39
48
  ```
40
49
 
41
50
  Then simply add the following actions in your Fastfile:
@@ -58,7 +67,7 @@ First install the gem:
58
67
  gem install icon-banner
59
68
  ```
60
69
 
61
- Then use it directly:
70
+ Then use it directly from the root of your app repository:
62
71
 
63
72
  ```bash
64
73
  icon-banner generate [options]
data/lib/icon_banner.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'icon_banner/appiconset'
2
+ require 'icon_banner/ic_launcher'
2
3
  require 'commander'
3
4
 
4
5
  module IconBanner
5
- VERSION = '0.1.0'
6
+ VERSION = '0.1.1'
6
7
  DESCRIPTION = 'IconBanner adds custom nice-looking banners over your mobile app icons'
7
8
 
8
9
  UI = FastlaneCore::UI
@@ -48,10 +49,12 @@ module IconBanner
48
49
 
49
50
  def self.generate(path, options)
50
51
  AppIconSet.new.generate(path, options)
52
+ IcLauncher.new.generate(path, options)
51
53
  end
52
54
 
53
55
  def self.restore(path)
54
56
  AppIconSet.new.restore(path)
57
+ IcLauncher.new.restore(path)
55
58
  end
56
59
 
57
60
  def self.available_options
@@ -1,82 +1,14 @@
1
+ require 'icon_banner/process'
2
+
1
3
  require 'fastlane_core'
2
4
  require 'mini_magick'
3
5
 
4
6
  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
7
+ class AppIconSet < Process
8
+ BASE_ICON_PATH = '/**/*.appiconset/*.png'
9
+ PLATFORM = 'iOS'
36
10
 
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)
11
+ def generate_banner(path, label, color, font)
80
12
  MiniMagick::Tool::Convert.new do |convert|
81
13
  convert.size '1024x1024'
82
14
  convert << 'xc:transparent'
@@ -104,29 +36,5 @@ module IconBanner
104
36
  combine.draw "affine 0.5,-0.5,0.5,0.5,-286,-286 text 0,0 \"#{label}\""
105
37
  end
106
38
  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
39
  end
132
40
  end
@@ -0,0 +1,76 @@
1
+ require 'icon_banner/process'
2
+
3
+ require 'fastlane_core'
4
+ require 'mini_magick'
5
+
6
+ module IconBanner
7
+ class IcLauncher < Process
8
+ BASE_ICON_PATH = '/**/ic_launcher*.png'
9
+ PLATFORM = 'Android (Legacy)'
10
+
11
+ def generate_banner(path, label, color, font)
12
+ size = 1024
13
+ font_size = 140 - ([label.length - 12, 0].max * 12)
14
+
15
+ # Start by computing the text
16
+ MiniMagick::Tool::Convert.new do |convert|
17
+ convert.size '1024x1024'
18
+ convert << 'xc:transparent'
19
+ convert << path
20
+ end
21
+
22
+ banner = MiniMagick::Image.new path
23
+
24
+ banner.combine_options do |combine|
25
+ combine.font font
26
+ combine.fill color
27
+ combine.gravity 'Center'
28
+ combine.pointsize font_size
29
+ combine.draw "text 0,0 \"#{label}\""
30
+ combine.trim
31
+ end
32
+
33
+ margin = 20
34
+ padding = 60
35
+ radius = 25
36
+ width = banner.width + padding * 2
37
+ height = 262
38
+
39
+ # Then restart the image and apply the banner
40
+ MiniMagick::Tool::Convert.new do |convert|
41
+ convert.size "#{size}x#{size}"
42
+ convert << 'xc:transparent'
43
+ convert << path
44
+ end
45
+
46
+ banner = MiniMagick::Image.new path
47
+
48
+ x_start = size - margin * 2 - width
49
+ x_end = size - margin
50
+ y_start = size - margin - height
51
+ y_end = size - margin
52
+ polygon = "roundRectangle #{x_start},#{y_start} #{x_end},#{y_end} #{radius},#{radius}"
53
+
54
+ banner.combine_options do |combine|
55
+ combine.fill 'rgba(0,0,0,0.25)'
56
+ combine.draw polygon
57
+ combine.blur '0x10'
58
+ end
59
+
60
+ banner.combine_options do |combine|
61
+ combine.fill 'white'
62
+ combine.draw polygon
63
+ end
64
+
65
+ x_middle = x_start + (x_end - x_start) / 2
66
+ y_middle = y_start + (y_end - y_start) / 2
67
+ banner.combine_options do |combine|
68
+ combine.font font
69
+ combine.fill color
70
+ combine.gravity 'Center'
71
+ combine.pointsize font_size
72
+ combine.draw "text #{x_middle - size / 2},#{y_middle - size / 2} \"#{label}\""
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,112 @@
1
+ require 'fastlane_core'
2
+ require 'mini_magick'
3
+
4
+ module IconBanner
5
+ class Process
6
+ BASE_ICON_PATH = '__TO OVERRIDE__'
7
+ PLATFORM = '__TO OVERRIDE__'
8
+
9
+ BACKUP_EXTENSION = '.bak'
10
+
11
+ def generate(path, options)
12
+ IconBanner.validate_libs!
13
+
14
+ restore(path) # restore in case it was already run before
15
+
16
+ app_icons = get_app_icons(path)
17
+
18
+ label = options[:label]
19
+ font = options[:font] || IconBanner.font_path
20
+
21
+ if app_icons.count > 0
22
+ UI.message "Generating #{self.class::PLATFORM} banners..."
23
+
24
+ app_icons.each do |icon_path|
25
+ UI.verbose "Processing #{icon_path}"
26
+ create_backup icon_path if options[:backup]
27
+
28
+ color = options[:color]
29
+ begin
30
+ color = find_base_color(icon_path)
31
+ UI.verbose "Color: #{color}"
32
+ end unless color
33
+
34
+ banner_file = Tempfile.new %w[banner .png]
35
+ generate_banner banner_file.path, label, color, font
36
+ process_icon icon_path, banner_file.path
37
+ banner_file.close
38
+
39
+ UI.verbose "Completed processing #{File.basename icon_path}"
40
+ UI.verbose ''
41
+ end
42
+
43
+ UI.message "Completed #{self.class::PLATFORM} generation."
44
+ else
45
+ UI.error('No icon found.')
46
+ UI.message self.class::BASE_ICON_PATH
47
+ end
48
+ end
49
+
50
+ def restore(path)
51
+ app_icons = get_app_icons(path)
52
+
53
+ if app_icons.count > 0
54
+ UI.message "Restoring #{self.class::PLATFORM} icons..."
55
+
56
+ app_icons.each do |icon_path|
57
+ UI.verbose "Restoring #{icon_path}"
58
+ restore_backup icon_path
59
+ end
60
+
61
+ UI.message "Completed #{self.class::PLATFORM} restore."
62
+ end
63
+ end
64
+
65
+ def get_app_icons(path)
66
+ app_icons = Dir.glob("#{path}#{self.class::BASE_ICON_PATH}")
67
+ app_icons.reject { |i| i[/\/Carthage\//] || i[/\/Pods\//] ||i[/\/Releases\//] }
68
+ end
69
+
70
+ def find_base_color(path)
71
+ color = MiniMagick::Tool::Convert.new do |convert|
72
+ convert << path
73
+ convert.colors 3
74
+ convert.background 'white'
75
+ convert.alpha 'remove'
76
+ convert << '-unique-colors'
77
+ convert.format '%[pixel:u]'
78
+ convert << 'xc:transparent'
79
+ convert << 'info:-'
80
+ end
81
+ color[/rgba?\([^)]*\)/]
82
+ end
83
+
84
+ def generate_banner(path, label, color, font)
85
+ UI.error 'Should not be run on base class'
86
+ end
87
+
88
+ def process_icon(icon_path, banner_path)
89
+ icon = MiniMagick::Image.open(icon_path)
90
+ banner = MiniMagick::Image.open(banner_path)
91
+ banner.resize "#{icon.width}x#{icon.height}"
92
+ icon.composite(banner).write(icon_path)
93
+ end
94
+
95
+ def create_backup(icon_path)
96
+ FileUtils.cp(icon_path, backup_path(icon_path))
97
+ end
98
+
99
+ def restore_backup(icon_path)
100
+ restore_path = backup_path(icon_path)
101
+ if File.exists?(restore_path)
102
+ FileUtils.cp(restore_path, icon_path)
103
+ File.delete restore_path
104
+ end
105
+ end
106
+
107
+ def backup_path(path)
108
+ ext = File.extname path
109
+ path.gsub(ext, BACKUP_EXTENSION + ext)
110
+ end
111
+ end
112
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icon-banner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Émile Bélair
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-21 00:00:00.000000000 Z
11
+ date: 2019-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fastlane
@@ -66,6 +66,8 @@ files:
66
66
  - bin/icon-banner
67
67
  - lib/icon_banner.rb
68
68
  - lib/icon_banner/appiconset.rb
69
+ - lib/icon_banner/ic_launcher.rb
70
+ - lib/icon_banner/process.rb
69
71
  homepage: https://github.com/ebelair/icon-banner
70
72
  licenses:
71
73
  - MIT