fastlane-plugin-framer 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +31 -26
- data/lib/fastlane/plugin/framer/actions/framer_action.rb +136 -28
- data/lib/fastlane/plugin/framer/version.rb +1 -1
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f483825329db96f65ffb7a835c9d859e458e25eba3f592312f5eecf9fc172b8
|
4
|
+
data.tar.gz: afc487ad12cec280e48a57fd8bd21314bd9eeba576eaf83c4bc64a8043b70a47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fe4de5acdb69e3bfd2ba3c3084bff037c4be88db36073c000917c7316ce0ee63ce4314aeb84069edec1cd180fea9b40d6d6dffa3e3496cff2135c814627f645
|
7
|
+
data.tar.gz: 42e043f83d7b16f9024e9e4aecd26b148cd04711c16b288edbdbf41085421bb3615505cf5ba511574d29a09af743474c40e58a1390a83bc1a6c0aeff0104af8d
|
data/README.md
CHANGED
@@ -26,9 +26,9 @@ You can specify the position and the size of the screen in the template and (opt
|
|
26
26
|
|
27
27
|
Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin.
|
28
28
|
|
29
|
-
There are
|
29
|
+
There are 4 lanes: 1º for a simple flow (`demo-1`), 2º with more languages and screens (`demo-2`), 3ª for android screenshots with rotation images and more them one frame(`demo-3`) and last for ios screenshots (`demo-4`).
|
30
30
|
|
31
|
-
Try them by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane
|
31
|
+
Try them by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane` and select lane.
|
32
32
|
|
33
33
|
## Configuration
|
34
34
|
|
@@ -40,16 +40,16 @@ In order to work, you need to configure each template and the text to draw in th
|
|
40
40
|
|
41
41
|
The **framer** action support 4 optional parameters (default values are used).
|
42
42
|
|
43
|
-
| Option | Description
|
44
|
-
| ----------------- |
|
45
|
-
| `source_folder` | path to the folder that contains raw screenshots and `text.json` file
|
46
|
-
| `template_folder` | path to the folder that contains the templates images and configuration
|
43
|
+
| Option | Description | Default |
|
44
|
+
| ----------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
45
|
+
| `source_folder` | path to the folder that contains raw screenshots and `text.json` file | `./fastlane/framer/screens` |
|
46
|
+
| `template_folder` | path to the folder that contains the templates images and configuration | `./fastlane/framer/templates` |
|
47
47
|
| `output_folder` | path to the folder that will contains the final images, framed. Used then by `deliver` | `./fastlane/screenshots` (default one for `deliver`) |
|
48
|
-
| `output_suffix` | filenam suffix for the framed images
|
48
|
+
| `output_suffix` | filenam suffix for the framed images | `-framed` |
|
49
49
|
|
50
50
|
### Template Configuration
|
51
51
|
|
52
|
-
In the template folder you choose, there must be a `
|
52
|
+
In the template folder you choose, there must be a `config.json` file (see [example](fastlane/demo-1/templates/config.json)). In there you will found
|
53
53
|
|
54
54
|
- a default configuration for all templates
|
55
55
|
- a custom configuration for each template (if needed).
|
@@ -76,36 +76,39 @@ There are keys for configuring screeshot and for the text.
|
|
76
76
|
|
77
77
|
#### Image
|
78
78
|
|
79
|
-
| Key
|
80
|
-
|
|
81
|
-
| `offset`
|
82
|
-
| `width`
|
83
|
-
| `add_below`
|
79
|
+
| Key | Type | Description |
|
80
|
+
| ----------- | ------: | -----------------------------------------------------------: |
|
81
|
+
| `offset` | String | Pixel position in the format `+[X value]+[Y value]` |
|
82
|
+
| `width` | Number | space available, in pixel, for the screen |
|
83
|
+
| `add_below` | Boolean | add screen below the template or not |
|
84
|
+
| `rotation` | Number | degrees for rotate image |
|
85
|
+
| `previous` | Object | same parameters as image, used to display the previous image |
|
86
|
+
| `next` | Object | same parameters as image, used to display the previous image |
|
84
87
|
|
85
88
|
#### Text
|
86
89
|
|
87
|
-
| Key
|
88
|
-
|
|
89
|
-
| `offset_x`
|
90
|
-
| `offset_y`
|
91
|
-
| `height`
|
92
|
-
| `size`
|
93
|
-
| `font`
|
94
|
-
| `color`
|
95
|
-
| `padding`
|
90
|
+
| Key | Type | Description |
|
91
|
+
| ---------- | -----: | -----------------------------------------------: |
|
92
|
+
| `offset_x` | Number | X position of the text block |
|
93
|
+
| `offset_y` | Number | Y position of the text block |
|
94
|
+
| `height` | Number | height of the text block |
|
95
|
+
| `size` | Number | font size |
|
96
|
+
| `font` | String | path of custom font file to use |
|
97
|
+
| `color` | String | color for the text in hex format (ex. `#545454`) |
|
98
|
+
| `padding` | Number | horizontal internal padding of the text block |
|
96
99
|
|
97
100
|
### Screenshots Text
|
98
101
|
|
99
102
|
If you want some text in the final framed images, you need to create a `text.json` file and put it with the raw device screenshots. It makes sense to commit this file in your repository.
|
100
103
|
|
101
|
-
`text.json` is a simple map where
|
102
|
-
The
|
104
|
+
`text.json` is a simple map where _key_ is the part of the screenshot filename (I suggest the same string you use with the `snapshot()` command on your UI tests.
|
105
|
+
The _value_ can be any strings.
|
103
106
|
|
104
107
|
### Colors
|
105
108
|
|
106
109
|
You can customize the color of the text and the background color applyed below the template (if you have transparencies on the template, you can fill them with the background color).
|
107
110
|
|
108
|
-
`colors.json` is a simple map where
|
111
|
+
`colors.json` is a simple map where _key_ is part of the screenshot filename. The _value_ is a map with 2 optional keys, _text_ and _background_.
|
109
112
|
|
110
113
|
```
|
111
114
|
{
|
@@ -119,16 +122,18 @@ You can customize the color of the text and the background color applyed below t
|
|
119
122
|
}
|
120
123
|
```
|
121
124
|
|
122
|
-
Default values can be defined inside the
|
125
|
+
Default values can be defined inside the _default_ map.
|
123
126
|
|
124
127
|
## Run tests for this plugin
|
125
128
|
|
126
129
|
To run both the tests, and code style validation, run
|
130
|
+
|
127
131
|
```
|
128
132
|
rake
|
129
133
|
```
|
130
134
|
|
131
135
|
To automatically fix many of the styling issues, use
|
136
|
+
|
132
137
|
```
|
133
138
|
rubocop -a
|
134
139
|
```
|
@@ -9,7 +9,9 @@ module Fastlane
|
|
9
9
|
attr_accessor :width, :height
|
10
10
|
|
11
11
|
attr_accessor :file
|
12
|
-
attr_accessor :imageOffset, :imageWidth, :imageBelow
|
12
|
+
attr_accessor :imageOffset, :imageWidth, :imageBelow, :imageRotation
|
13
|
+
attr_accessor :imagePreviousOffset, :imagePreviousWidth, :imagePreviousRotation
|
14
|
+
attr_accessor :imageNextOffset, :imageNextWidth, :imageNextRotation
|
13
15
|
attr_accessor :textOffsetX, :textOffsetY, :textWidth, :textHeight, :textPadding, :textSize, :textFont
|
14
16
|
end
|
15
17
|
|
@@ -35,6 +37,7 @@ module Fastlane
|
|
35
37
|
source_folder = params[:source_folder]
|
36
38
|
output_folder = params[:output_folder]
|
37
39
|
template_folder = params[:template_folder]
|
40
|
+
list_files = Dir.glob("#{source_folder}/**/*.png").sort
|
38
41
|
templates = []
|
39
42
|
platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
|
40
43
|
|
@@ -44,8 +47,8 @@ module Fastlane
|
|
44
47
|
|
45
48
|
# Process each screen
|
46
49
|
UI.success "Processing screenshots from #{source_folder}"
|
47
|
-
|
48
|
-
UI.message "Processing #{file}"
|
50
|
+
list_files.each_with_index do |file, index|
|
51
|
+
UI.message "Processing #{file} index #{index}"
|
49
52
|
|
50
53
|
template = self.find_template(templates, file, platform)
|
51
54
|
if template.nil?
|
@@ -57,14 +60,14 @@ module Fastlane
|
|
57
60
|
text = self.find_text(source_folder, file)
|
58
61
|
UI.verbose "Using text: #{text}"
|
59
62
|
|
60
|
-
colors = self.find_colors(source_folder, file)
|
63
|
+
colors = self.find_colors(source_folder, file, template_folder)
|
61
64
|
UI.verbose "Using colors: #{colors}"
|
62
65
|
|
63
66
|
output = self.find_output(source_folder, file, output_folder, params[:output_suffix])
|
64
67
|
UI.verbose "Saving to: #{output}"
|
65
68
|
|
66
|
-
# Do the magic
|
67
|
-
self.combine(file, template, colors, text, output)
|
69
|
+
# # Do the magic
|
70
|
+
self.combine(file, template, colors, text, output, list_files, index)
|
68
71
|
|
69
72
|
UI.verbose "Framed screenshot #{output}"
|
70
73
|
end
|
@@ -74,7 +77,7 @@ module Fastlane
|
|
74
77
|
end
|
75
78
|
|
76
79
|
def self.load_templates(template_folder)
|
77
|
-
json_file_path = "#{template_folder}/
|
80
|
+
json_file_path = "#{template_folder}/config.json"
|
78
81
|
|
79
82
|
UI.user_error!("Missing Config.json file in template folder") unless File.exist?(json_file_path)
|
80
83
|
|
@@ -86,7 +89,6 @@ module Fastlane
|
|
86
89
|
|
87
90
|
# Detect available templates
|
88
91
|
templates = []
|
89
|
-
|
90
92
|
Dir.glob("#{template_folder}/**/*.png") do |file|
|
91
93
|
|
92
94
|
name = File.basename(file, ".png")
|
@@ -110,18 +112,30 @@ module Fastlane
|
|
110
112
|
next
|
111
113
|
end
|
112
114
|
|
113
|
-
#
|
114
|
-
template.imageOffset
|
115
|
-
template.imageWidth
|
116
|
-
template.imageBelow
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
template.
|
121
|
-
template.
|
122
|
-
template.
|
123
|
-
|
124
|
-
|
115
|
+
# set image
|
116
|
+
template.imageOffset = (config_custom['image'] && config_custom['image']['offset']) || (config_default['image'] && config_default['image']['offset'])
|
117
|
+
template.imageWidth = (config_custom['image'] && config_custom['image']['width']) || (config_default['image'] && config_default['image']['width'])
|
118
|
+
template.imageBelow = (config_custom['image'] && config_custom['image']['add_below']) || (config_default['image'] && config_default['image']['add_below']) || false
|
119
|
+
template.imageRotation = (config_custom['image'] && config_custom['image']['rotation']) || (config_default['image'] && config_default['image']['rotation'])
|
120
|
+
|
121
|
+
# set image back
|
122
|
+
template.imagePreviousOffset = (config_custom['image']['previous'] && config_custom['image']['previous']['offset']) || (config_default['image']['previous'] && config_default['image']['previous']['offset'])
|
123
|
+
template.imagePreviousWidth = (config_custom['image']['previous'] && config_custom['image']['previous']['width']) || (config_default['image']['previous'] && config_default['image']['previous']['width'])
|
124
|
+
template.imagePreviousRotation = (config_custom['image']['previous'] && config_custom['image']['previous']['rotation']) || (config_default['image']['previous'] && config_default['image']['previous']['rotation'])
|
125
|
+
|
126
|
+
# set image next
|
127
|
+
template.imageNextOffset = (config_custom['image']['next'] && config_custom['image']['next']['offset']) || (config_default['image']['next'] && config_default['image']['next']['offset'])
|
128
|
+
template.imageNextWidth = (config_custom['image']['next'] && config_custom['image']['next']['width']) || (config_default['image']['next'] && config_default['image']['next']['width'])
|
129
|
+
template.imageNextRotation = (config_custom['image']['next'] && config_custom['image']['next']['rotation']) || (config_default['image']['next'] && config_default['image']['next']['rotation'])
|
130
|
+
|
131
|
+
# set font
|
132
|
+
template.textFont = (config_custom['text'] && config_custom['text']['font']) || (config_default['text'] && config_default['text']['font'])
|
133
|
+
template.textSize = (config_custom['text'] && config_custom['text']['size']) || (config_default['text'] && config_default['text']['size'])
|
134
|
+
template.textWidth = (config_custom['text'] && config_custom['text']['width']) || (config_default['text'] && config_default['text']['width'])
|
135
|
+
template.textHeight = (config_custom['text'] && config_custom['text']['height']) || (config_default['text'] && config_default['text']['height'])
|
136
|
+
template.textPadding = (config_custom['text'] && config_custom['text']['padding']) || (config_default['text'] && config_default['text']['padding']) || 0
|
137
|
+
template.textOffsetX = (config_custom['text'] && config_custom['text']['offset_x']) || (config_default['text'] && config_default['text']['offset_x']) || 0
|
138
|
+
template.textOffsetY = (config_custom['text'] && config_custom['text']['offset_y']) || (config_default['text'] && config_default['text']['offset_y']) || 0
|
125
139
|
|
126
140
|
templates << template
|
127
141
|
end
|
@@ -163,7 +177,7 @@ module Fastlane
|
|
163
177
|
return result.last if result
|
164
178
|
end
|
165
179
|
|
166
|
-
def self.find_colors(source_dir, screenshot_file)
|
180
|
+
def self.find_colors(source_dir, screenshot_file, colors_dir)
|
167
181
|
|
168
182
|
# Default values
|
169
183
|
colors = Colors.new
|
@@ -172,7 +186,7 @@ module Fastlane
|
|
172
186
|
|
173
187
|
# Read values from file
|
174
188
|
directory = File.dirname(screenshot_file)
|
175
|
-
colors_path = File.join(
|
189
|
+
colors_path = File.join(colors_dir, "colors.json")
|
176
190
|
|
177
191
|
while directory.start_with?(source_dir) && !File.exist?(colors_path) do
|
178
192
|
directory = File.dirname(directory)
|
@@ -226,7 +240,16 @@ module Fastlane
|
|
226
240
|
return file_path
|
227
241
|
end
|
228
242
|
|
229
|
-
|
243
|
+
# Magic is HERE
|
244
|
+
def self.combine(screenshot_file, template, colors, text, output_file, list_files, index)
|
245
|
+
|
246
|
+
# Get list lenght
|
247
|
+
list_lenght = list_files.length()
|
248
|
+
|
249
|
+
# Var images
|
250
|
+
screenshot_img_back = nil
|
251
|
+
screenshot_img = nil
|
252
|
+
screenshot_img_next = nil
|
230
253
|
|
231
254
|
# Prepare base image
|
232
255
|
result_img = MiniMagick::Image.open("#{Framer::ROOT}/assets/background.png")
|
@@ -243,20 +266,86 @@ module Fastlane
|
|
243
266
|
|
244
267
|
# Get template image
|
245
268
|
template_img = MiniMagick::Image.open(template.file)
|
269
|
+
|
270
|
+
# Get back screenshot
|
271
|
+
unless template.imagePreviousOffset.nil?
|
272
|
+
if list_lenght >= index -1
|
273
|
+
screenshot_img_back = MiniMagick::Image.open(list_files[index -1]).auto_orient
|
274
|
+
screenshot_img_back.resize "#{template.imagePreviousWidth}x"
|
275
|
+
unless template.imagePreviousRotation.nil?
|
276
|
+
screenshot_img_back.combine_options do |cmd|
|
277
|
+
cmd.background "rgba(255,255,255,0.0)" # transparent
|
278
|
+
cmd.rotate(template.imagePreviousRotation.to_f)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
else
|
282
|
+
UI.error "Unable to find back screenshot index #{index-1} in #{list_lenght}"
|
283
|
+
end
|
284
|
+
end
|
246
285
|
|
247
286
|
# Get screenshot image
|
248
287
|
screenshot_img = MiniMagick::Image.open(screenshot_file).auto_orient
|
249
|
-
|
288
|
+
|
250
289
|
# Resize screenshot to fit template
|
251
290
|
screenshot_img.resize "#{template.imageWidth}x"
|
291
|
+
|
292
|
+
# rotate screenshot
|
293
|
+
unless template.imageRotation.nil?
|
294
|
+
screenshot_img.combine_options do |cmd|
|
295
|
+
cmd.background "rgba(255,255,255,0.0)" # transparent
|
296
|
+
cmd.rotate(template.imageRotation.to_f)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Get next screenshot
|
301
|
+
unless template.imageNextOffset.nil?
|
302
|
+
if list_lenght >= index + 1
|
303
|
+
image_path = list_files[index+1]
|
304
|
+
list_files.each_with_index do |_file, _index|
|
305
|
+
if _index === index
|
306
|
+
print("file: ", _file, " index ", _index, " my index ", index)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
# print("aqui jovem: ", image_path, " list_lenght ", list_lenght, " index ", index)
|
310
|
+
screenshot_img_next = MiniMagick::Image.open(list_files[index]).auto_orient
|
311
|
+
screenshot_img_next.resize "#{template.imageNextWidth}x"
|
312
|
+
unless template.imageNextRotation.nil?
|
313
|
+
screenshot_img_next.combine_options do |cmd|
|
314
|
+
cmd.background "rgba(255,255,255,0.0)" # transparent
|
315
|
+
cmd.rotate(template.imageNextRotation.to_f)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
else
|
319
|
+
UI.error "Unable to find next screenshot index #{index+1} in #{list_lenght}"
|
320
|
+
end
|
321
|
+
end
|
252
322
|
|
253
323
|
# Put screenshot over template
|
254
324
|
if template.imageBelow
|
255
325
|
|
326
|
+
# Screenshot back
|
327
|
+
unless screenshot_img_back.nil?
|
328
|
+
result_img = result_img.composite(screenshot_img_back) do |c|
|
329
|
+
c.compose "Over"
|
330
|
+
c.geometry template.imagePreviousOffset.to_s
|
331
|
+
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
256
335
|
# Screenshot first
|
257
336
|
result_img = result_img.composite(screenshot_img) do |c|
|
258
337
|
c.compose "Over"
|
259
338
|
c.geometry template.imageOffset.to_s
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
# Screenshot next
|
343
|
+
unless screenshot_img_next.nil?
|
344
|
+
result_img = result_img.composite(screenshot_img_next) do |c|
|
345
|
+
c.compose "Over"
|
346
|
+
c.geometry template.imageNextOffset.to_s
|
347
|
+
|
348
|
+
end
|
260
349
|
end
|
261
350
|
|
262
351
|
# Template second
|
@@ -271,10 +360,29 @@ module Fastlane
|
|
271
360
|
c.compose "Over"
|
272
361
|
end
|
273
362
|
|
274
|
-
|
363
|
+
# Screenshot back
|
364
|
+
unless screenshot_img_back.nil?
|
365
|
+
result_img = result_img.composite(screenshot_img_back) do |c|
|
366
|
+
c.compose "Over"
|
367
|
+
c.geometry template.imagePreviousOffset.to_s
|
368
|
+
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Screenshot first
|
275
373
|
result_img = result_img.composite(screenshot_img) do |c|
|
276
374
|
c.compose "Over"
|
277
375
|
c.geometry template.imageOffset.to_s
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
# Screenshot next
|
380
|
+
unless screenshot_img_next.nil?
|
381
|
+
result_img = result_img.composite(screenshot_img_next) do |c|
|
382
|
+
c.compose "Over"
|
383
|
+
c.geometry template.imageNextOffset.to_s
|
384
|
+
|
385
|
+
end
|
278
386
|
end
|
279
387
|
|
280
388
|
end
|
@@ -294,7 +402,7 @@ module Fastlane
|
|
294
402
|
text_img.combine_options do |c|
|
295
403
|
c.font text_font
|
296
404
|
c.pointsize template.textSize.to_s
|
297
|
-
c.gravity "
|
405
|
+
c.gravity "NorthWest"
|
298
406
|
c.draw "text 0,0 '#{text}'"
|
299
407
|
c.fill colors.text.to_s
|
300
408
|
end
|
@@ -351,11 +459,11 @@ module Fastlane
|
|
351
459
|
#####################################################
|
352
460
|
|
353
461
|
def self.description
|
354
|
-
"Create images combining app screenshots to templates to make a nice \'screenshot\' to upload in App Store"
|
462
|
+
"Create images combining app screenshots to templates to make a nice \'screenshot\' to upload in App Store and Google Play"
|
355
463
|
end
|
356
464
|
|
357
465
|
def self.authors
|
358
|
-
["DrAL3X"]
|
466
|
+
["DrAL3X", "AzureRodrigo"]
|
359
467
|
end
|
360
468
|
|
361
469
|
def self.available_options
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-framer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DrAL3X
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 1.100.0
|
125
|
-
description:
|
125
|
+
description:
|
126
126
|
email: alessandro.calzavara@gmail.com
|
127
127
|
executables: []
|
128
128
|
extensions: []
|
@@ -139,7 +139,7 @@ homepage: https://github.com/spreaker/fastlane-framer-plugin
|
|
139
139
|
licenses:
|
140
140
|
- MIT
|
141
141
|
metadata: {}
|
142
|
-
post_install_message:
|
142
|
+
post_install_message:
|
143
143
|
rdoc_options: []
|
144
144
|
require_paths:
|
145
145
|
- lib
|
@@ -154,9 +154,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
154
|
- !ruby/object:Gem::Version
|
155
155
|
version: '0'
|
156
156
|
requirements: []
|
157
|
-
|
158
|
-
|
159
|
-
signing_key:
|
157
|
+
rubygems_version: 3.1.2
|
158
|
+
signing_key:
|
160
159
|
specification_version: 4
|
161
160
|
summary: Create images combining app screenshots with templates to make nice pictures
|
162
161
|
for the App Store
|