xc_html_generator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 25460904a9b2cb299009f1328895c4510cb5926e293e1cae9d47cbc569c9aa16
4
+ data.tar.gz: 25f2bc9ab1020212c535b02b7eb27d6e2c07fc9a1b4a4c0d4942169a346aadcd
5
+ SHA512:
6
+ metadata.gz: 10f784b665bd07a0e374ada0727b3798c11238cb2ba7449c9050ca76621e3010deae41ddd83f1480d535755b7f9aa76f091246335ebe99e9d2d58f8c05e9f767
7
+ data.tar.gz: 4572bc001b4da3654baf30f318467472f42ae97436e0f0966645654d8f19c859a1655677c84615f347ff7034de1ef0956062a51d4055b357e91fa2111910a6cc
@@ -0,0 +1,285 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>fastlane/snapshot</title>
5
+ <meta charset="UTF-8">
6
+ <style type="text/css">
7
+ * {
8
+ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
9
+ font-weight: 300;
10
+ }
11
+ #sortMenu {
12
+ overflow: hidden;
13
+ border: 1px solid #ccc;
14
+ background-color: #f1f1f1;
15
+ display: none;
16
+ }
17
+ #sortMenu button {
18
+ background-color: inherit;
19
+ float: left;
20
+ border: none;
21
+ outline: none;
22
+ cursor: pointer;
23
+ padding: 14px 16px;
24
+ font-size: 17px;
25
+ }
26
+ #sortMenu button:hover {
27
+ background-color: #ddd;
28
+ }
29
+ #sortMenu button.active {
30
+ background-color: #ccc;
31
+ }
32
+ .deviceName {
33
+ display: block;
34
+ font-size: 30px;
35
+ padding-bottom: 24px;
36
+ padding-top: 45px;
37
+ }
38
+ .screenshot {
39
+ cursor: pointer;
40
+ border: 1px #EEE solid;
41
+ z-index: 0;
42
+ }
43
+ .caption {
44
+ font-size: 24px;
45
+ padding-bottom: 24px;
46
+ padding-top: 30px;
47
+ }
48
+ h1, h2 {
49
+ font-weight: bold;
50
+ }
51
+ th {
52
+ text-align: left;
53
+ }
54
+ td {
55
+ text-align: center;
56
+ min-width: 200px;
57
+ }
58
+ #overlay {
59
+ position:fixed;
60
+ top:0;
61
+ left:0;
62
+ background:rgba(0,0,0,0.8);
63
+ z-index:5;
64
+ width:100%;
65
+ height:100%;
66
+ display:none;
67
+ cursor: zoom-out;
68
+ text-align: center;
69
+ }
70
+ #imageDisplay {
71
+ height: auto;
72
+ width: auto;
73
+ z-index: 10;
74
+ cursor: pointer;
75
+ }
76
+ #imageInfo {
77
+ background: none repeat scroll 0 0 rgba(0, 0, 0, 0.2);
78
+ border-radius: 5px;
79
+ color: white;
80
+ margin: 20px;
81
+ padding: 10px;
82
+ position: absolute;
83
+ right: 0;
84
+ top: 0;
85
+ width: 250px;
86
+ z-index: -1;
87
+ }
88
+ #imageInfo:hover {
89
+ z-index: 20;
90
+ }
91
+ </style>
92
+ </head>
93
+ <body>
94
+ <div id="sortMenu">
95
+ <button id="defaultTab" class="tabLink" onclick="openTab(event, 'byLanguage')">By Language</button>
96
+ <button class="tabLink" onclick="openTab(event, 'byScreen')">By Screen</button>
97
+ </div>
98
+ <div id="byLanguage" class="tabContent"><h1 class="tabTitle">By Language:</h1><% image_counter = 0 %><% @data_by_language.each do |language, content| %>
99
+ <h2 id="<%= language %>"><%= language %></h2>
100
+ <hr>
101
+ <table><% content.each do |device_name, screens| %>
102
+ <tr>
103
+ <th colspan="<%= screens.count %>">
104
+ <a id="<%= language %>-<%= device_name %>" class="deviceName" href="#<%= language %>-<%= device_name %>"><%= device_name %></a>
105
+ </th>
106
+ </tr>
107
+ <tr><% screens.each do |screen_path| %><% next if screen_path.include?"_framed.png" %>
108
+ <td><% image_counter += 1 %>
109
+ <a href="<%= screen_path %>" target="_blank" class="screenshotLink">
110
+ <img class="screenshot" src="<%= screen_path %>" style="width: 100%;" alt="<%= language %> <%= device_name %>" data-tab="1" data-counter="<%= image_counter %>">
111
+ </a>
112
+ </td><% end %>
113
+ </tr><% end %>
114
+ </table><% end %>
115
+ </div>
116
+ <div id="byScreen" class="tabContent"><h1 class="tabTitle">By Screen:</h1><% image_counter = 0 %><% @data_by_screen.each do |screen, content| %>
117
+ <h2 id="<%= screen %>" class="screen"><%= screen %></h2>
118
+ <hr>
119
+ <table><% content.each do |device_name, screens| %>
120
+ <tr>
121
+ <th colspan="<%= screens.count %>">
122
+ <a id="<%= screen %>-<%= device_name %>" class="deviceName" href="#<%= screen %>-<%= device_name %>"><%= device_name %></a>
123
+ </th>
124
+ </tr>
125
+ <tr><% screens.each do |language, screen_path| %><% next if screen_path.include?"_framed.png" %>
126
+ <td><% image_counter += 1 %>
127
+ <a href="<%= screen_path %>" target="_blank" class="screenshotLink">
128
+ <img class="screenshot" src="<%= screen_path %>" style="width: 100%;" alt="<%= language %> <%= device_name %>" data-tab="2" data-counter="<%= image_counter %>">
129
+ </a>
130
+ <div class="caption"><%= language %></div>
131
+ </td><% end %>
132
+ </tr><% end %>
133
+ </table><% end %>
134
+ </div>
135
+ <div id="overlay">
136
+ <img id="imageDisplay" src="" alt="" />
137
+ <div id="imageInfo"></div>
138
+ </div>
139
+ <script type="text/javascript">
140
+ var overlay = document.getElementById('overlay');
141
+ var imageDisplay = document.getElementById('imageDisplay');
142
+ var imageInfo = document.getElementById('imageInfo');
143
+ var screenshotLink = document.getElementsByClassName('screenshotLink');
144
+
145
+ window.onload = setup();
146
+
147
+ function setup() {
148
+ var i, menu, tabTitles;
149
+
150
+ // Since JS is enabled, show sort menu and hide tab titles
151
+ menu = document.getElementById("sortMenu");
152
+ menu.style.display = "block";
153
+
154
+ tabTitles = document.getElementsByClassName("tabTitle");
155
+ for (i = 0; i < tabTitles.length; i++) {
156
+ tabTitles[i].style.display = "none";
157
+ }
158
+
159
+ doClick(document.getElementById("defaultTab"));
160
+ }
161
+
162
+ function getCurrentTab() {
163
+ var i, tabs;
164
+ tabs = document.getElementsByClassName("tabContent");
165
+ for (i = 0; i < tabs.length; i++) {
166
+ if (tabs[i].style.display != "none") {
167
+ return i + 1;
168
+ }
169
+ }
170
+ return 1; // fallback
171
+ }
172
+
173
+ function openTab(evt, tabName) {
174
+ var i, tabContent, tabLinks;
175
+ tabs = document.getElementsByClassName("tabContent");
176
+ for (i = 0; i < tabs.length; i++) {
177
+ tabs[i].style.display = "none";
178
+ }
179
+ tabLinks = document.getElementsByClassName("tabLink");
180
+ for (i = 0; i < tabLinks.length; i++) {
181
+ tabLinks[i].className = tabLinks[i].className.replace(" active", "");
182
+ }
183
+ document.getElementById(tabName).style.display = "block";
184
+ evt.currentTarget.className += " active";
185
+ }
186
+
187
+ function doClick(el) {
188
+ if (document.createEvent) {
189
+ var evObj = document.createEvent('MouseEvents', true);
190
+ evObj.initMouseEvent("click", false, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
191
+ el.dispatchEvent(evObj);
192
+ } else if (document.createEventObject) { //IE
193
+ var evObj = document.createEventObject();
194
+ el.fireEvent('onclick', evObj);
195
+ }
196
+ }
197
+
198
+ for (index = 0; index < screenshotLink.length; ++index) {
199
+ screenshotLink[index].addEventListener('click', function(e) {
200
+ e.preventDefault();
201
+
202
+ var img = e.target;
203
+ if (e.target.tagName == 'A') {
204
+ img = e.target.children[0];
205
+ }
206
+
207
+ // beautify
208
+ var tmpImg = new Image();
209
+ tmpImg.src = img.src;
210
+ imageDisplay.style.height = 'auto';
211
+ imageDisplay.style.width = 'auto';
212
+ imageDisplay.style.paddingTop = 0;
213
+ if (window.innerHeight < tmpImg.height) {
214
+ imageDisplay.style.height = document.documentElement.clientHeight+'px';
215
+ } else if (window.innerWidth < tmpImg.width) {
216
+ imageDisplay.style.width = document.documentElement.clientWidth;+'px';
217
+ } else {
218
+ imageDisplay.style.paddingTop = parseInt((window.innerHeight - tmpImg.height) / 2)+'px';
219
+ }
220
+
221
+ imageDisplay.src = img.src;
222
+ imageDisplay.alt = img.alt;
223
+ imageDisplay.dataset.counter = img.dataset.counter;
224
+
225
+ imageInfo.innerHTML = '<h3>'+img.alt+'</h3>';
226
+ imageInfo.innerHTML += decodeURI(img.src.split("/").pop());
227
+ imageInfo.innerHTML += '<br />'+tmpImg.height+'&times;'+tmpImg.width+'px';
228
+
229
+ overlay.style.display = "block";
230
+ });
231
+ }
232
+
233
+ imageDisplay.addEventListener('click', function(e) {
234
+ e.stopPropagation(); // !
235
+
236
+ overlay.style.display = "none";
237
+
238
+ img_tab = parseInt(getCurrentTab());
239
+ img_counter = parseInt(e.target.dataset.counter) + 1;
240
+ try {
241
+ link = document.body.querySelector('img[data-tab="'+img_tab+'"][data-counter="'+img_counter+'"]').parentNode;
242
+ } catch (e) {
243
+ try {
244
+ link = document.body.querySelector('img[data-tab="'+img_tab+'"][data-counter="0"]').parentNode;
245
+ } catch (e) {
246
+ return false;
247
+ }
248
+ }
249
+ doClick(link);
250
+ });
251
+
252
+ overlay.addEventListener('click', function(e) {
253
+ overlay.style.display = "none";
254
+ })
255
+
256
+ function keyPressed(e) {
257
+ e = e || window.event;
258
+ var charCode = e.keyCode || e.which;
259
+ switch(charCode) {
260
+ case 27: // Esc
261
+ overlay.style.display = "none";
262
+ break;
263
+ case 34: // Page Down
264
+ case 39: // Right arrow
265
+ case 54: // Keypad right
266
+ case 76: // l
267
+ case 102: // Keypad right
268
+ e.preventDefault();
269
+ doClick(imageDisplay);
270
+ break;
271
+ case 33: // Page up
272
+ case 37: // Left arrow
273
+ case 52: // Keypad left
274
+ case 72: // h
275
+ case 100: // Keypad left
276
+ e.preventDefault();
277
+ document.getElementById('imageDisplay').dataset.counter -= 2; // hacky
278
+ doClick(imageDisplay);
279
+ break;
280
+ }
281
+ };
282
+ document.body.addEventListener('keydown', keyPressed);
283
+ </script>
284
+ </body>
285
+ </html>
@@ -0,0 +1,125 @@
1
+
2
+
3
+ class HtmlGenerator
4
+ require 'erb'
5
+ require 'fastimage'
6
+ require 'xcresult'
7
+ require 'fastlane'
8
+
9
+ attr_accessor :screenshots_path
10
+
11
+ def initialize(params = {})
12
+ @screenshots_path = params.fetch(:screenshots_path, path)
13
+ end
14
+
15
+ def path
16
+ Dir.pwd
17
+ end
18
+
19
+ def html_path
20
+ File.join(path, "lib", "html", "page.html.erb")
21
+ end
22
+
23
+ def result_path
24
+ path
25
+ end
26
+ # Tweet
27
+ # @return [String]
28
+ def generate
29
+
30
+ screens_path = screenshots_path
31
+
32
+ @data_by_language = {}
33
+ @data_by_screen = {}
34
+ Dir[File.join(screens_path, "*")].sort.each do |device_name_folders|
35
+ device_name = File.basename(device_name_folders)
36
+ Dir[File.join(device_name_folders, "*")].sort.each do |language_folder|
37
+ language = File.basename(language_folder)
38
+ Dir[File.join(language_folder, '*.png')].sort.each do |screenshot|
39
+ file_name = File.basename(screenshot)
40
+ available_devices.each do |key_name, output_name|
41
+ next unless device_name.include?(key_name)
42
+ # This screenshot is from this device
43
+
44
+ @data_by_language[language] ||= {}
45
+ @data_by_language[language][output_name] ||= []
46
+
47
+ screen_name = file_name.sub(key_name + '-', '').sub('.png', '')
48
+ @data_by_screen[screen_name] ||= {}
49
+ @data_by_screen[screen_name][output_name] ||= {}
50
+
51
+ resulting_path = screenshot
52
+ @data_by_language[language][output_name] << resulting_path
53
+ @data_by_screen[screen_name][output_name][language] = resulting_path
54
+ break # to not include iPhone 6 and 6 Plus (name is contained in the other name)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ html = ERB.new(File.read(html_path)).result(binding) # https://web.archive.org/web/20160430190141/www.rrn.dk/rubys-erb-templating-system
60
+
61
+ export_path = "#{screens_path}/screenshots.html"
62
+
63
+ File.write(export_path, html)
64
+
65
+ export_path = File.expand_path(export_path)
66
+ p "Successfully created HTML file with an overview of all the screenshots: '#{export_path}'"
67
+ #system("open '#{export_path}'") unless Snapshot.config[:skip_open_summary]
68
+ end
69
+
70
+ def xcode_9_and_above_device_name_mappings
71
+ {
72
+ # snapshot in Xcode 9 saves screenshots with the SIMULATOR_DEVICE_NAME
73
+ # which includes spaces
74
+ 'iPhone 12 Pro Max' => "iPhone 12 Pro Max",
75
+ 'iPhone 12 Pro' => "iPhone 12 Pro",
76
+ 'iPhone 12 mini' => "iPhone 12 mini",
77
+ 'iPhone 12' => "iPhone 12",
78
+ 'iPhone 11 Pro Max' => "iPhone 11 Pro Max",
79
+ 'iPhone 11 Pro' => "iPhone 11 Pro",
80
+ 'iPhone 11' => "iPhone 11",
81
+ 'iPhone XS Max' => "iPhone XS Max",
82
+ 'iPhone XS' => "iPhone XS",
83
+ 'iPhone XR' => "iPhone XR",
84
+ 'iPhone 8 Plus' => "iPhone 8 Plus",
85
+ 'iPhone 8' => "iPhone 8",
86
+ 'iPhone X' => "iPhone X",
87
+ 'iPhone 7 Plus' => "iPhone 7 Plus (5.5-Inch)",
88
+ 'iPhone 7' => "iPhone 7 (4.7-Inch)",
89
+ 'iPhone 6s Plus' => "iPhone 6s Plus (5.5-Inch)",
90
+ 'iPhone 6 Plus' => "iPhone 6 Plus (5.5-Inch)",
91
+ 'iPhone 6s' => "iPhone 6s (4.7-Inch)",
92
+ 'iPhone 6' => "iPhone 6 (4.7-Inch)",
93
+ 'iPhone 5s' => "iPhone 5s (4-Inch)",
94
+ 'iPhone 5' => "iPhone 5 (4-Inch)",
95
+ 'iPhone SE' => "iPhone SE",
96
+ 'iPhone 4s' => "iPhone 4s (3.5-Inch)",
97
+ 'iPad 2' => 'iPad 2',
98
+ 'iPad Air (3rd generation)' => 'iPad Air (3rd generation)',
99
+ 'iPad Air 2' => 'iPad Air 2',
100
+ 'iPad Air' => 'iPad Air',
101
+ 'iPad (5th generation)' => 'iPad (5th generation)',
102
+ 'iPad (7th generation)' => 'iPad (7th generation)',
103
+ 'iPad Pro (9.7-inch)' => 'iPad Pro (9.7-inch)',
104
+ 'iPad Pro (9.7 inch)' => 'iPad Pro (9.7-inch)', # iOS 10.3.1 simulator
105
+ 'iPad Pro (10.5-inch)' => 'iPad Pro (10.5-inch)',
106
+ 'iPad Pro (11-inch) (2nd generation)' => 'iPad Pro (11-inch) (2nd generation)',
107
+ 'iPad Pro (11-inch)' => 'iPad Pro (11-inch)',
108
+ 'iPad Pro (12.9-inch) (4th generation)' => 'iPad Pro (12.9-inch) (4th generation)',
109
+ 'iPad Pro (12.9-inch) (3rd generation)' => 'iPad Pro (12.9-inch) (3rd generation)',
110
+ 'iPad Pro (12.9-inch) (2nd generation)' => 'iPad Pro (12.9-inch) (2nd generation)',
111
+ 'iPad Pro (12.9-inch)' => 'iPad Pro (12.9-inch)',
112
+ 'iPad Pro (12.9 inch)' => 'iPad Pro (12.9-inch)', # iOS 10.3.1 simulator
113
+ 'iPad Pro' => 'iPad Pro (12.9-inch)', # iOS 9.3 simulator
114
+ 'Apple TV 1080p' => 'Apple TV',
115
+ 'Apple TV 4K (at 1080p)' => 'Apple TV 4K (at 1080p)',
116
+ 'Apple TV 4K' => 'Apple TV 4K',
117
+ 'Apple TV' => 'Apple TV',
118
+ 'Mac' => 'Mac'
119
+ }
120
+ end
121
+
122
+ def available_devices
123
+ return xcode_9_and_above_device_name_mappings
124
+ end
125
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xc_html_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kostyantin Ishchenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A simple gem that genarate html from xcparse result
14
+ email: ko7tyantin@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/html/page.html.erb
20
+ - lib/xc_html_generator.rb
21
+ homepage: https://rubygems.org/gems/xc_html_generator
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubygems_version: 3.2.16
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Helper gem for xcparse
44
+ test_files: []