UberGallery — это простой PHP-скрипт, который создает красивую галерею веб-изображений, генерируя миниатюры оригинальных изображений на лету. Вам просто нужно загрузить изображения в определенный каталог, и они будут выбраны для создания фотогалереи.
Наша цель — создать модуль, который использует скрипт UberGallery для генерации галереи, но способом OpenCart. В конце вы должны быть в состоянии настроить параметры, такие как ширина миниатюры, высота миниатюры и тому подобное. Исходя из этого, он создаст блок галереи изображений на интерфейсных страницах.
Сегодня мы пройдем через внутреннюю настройку, в которой мы создадим файлы, необходимые для создания пользовательской формы конфигурации в части внутреннего модуля. Я предполагаю, что вы знакомы с базовым процессом разработки модулей в OpenCart, так как мы пропустим основы этапов создания модулей. Вот хорошая статья, объясняющая основы модулей OpenCart, если вы хотите изучить это.
Я предполагаю, что вы используете последнюю версию OpenCart, поэтому убедитесь, что она у вас есть, чтобы вы могли следовать образцам кода.
Настройка файла — в двух словах
Давайте быстро пройдемся по настройке файла, необходимой для серверной части.
-
admin/controller/module/uber_gallery.php:
это файл контроллера, который обеспечивает логику приложения обычного контроллера в OpenCart. -
admin/language/english/module/uber_gallery.php:
Это языковой файл, который помогает настроить языковые метки. -
admin/view/template/module/uber_gallery.tpl:
это файл шаблона представления, который содержит XHTML формы конфигурации. -
system/library/uberGallery:
это сам компонент UberGallery.
Вот список файлов, которые мы собираемся реализовать сегодня. Он создаст пользовательскую форму конфигурации для нашего модуля UberGallery, чтобы вы могли настраивать различные параметры из серверной части.
Не теряя времени, я сразу же погрузлюсь в отвратительные вещи.
Настройка файлов внутреннего модуля
Прежде чем мы продолжим создавать наши собственные файлы модулей, загрузите UberGallery с официального сайта и скопируйте каталог resource
таким образом, чтобы он выглядел как system/library/uberGallery/resources
.
Теперь создайте файловую system/library/uberGallery/resources/oc.galleryConfig.ini
со следующим содержимым.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
;
;
[basic_settings]
cache_expiration = [cache_expiration] ;
;
enable_pagination = true ;
paginator_threshold = 10 ;
;
thumbnail_width = [thumbnail_width] ;
thumbnail_height = [thumbnail_height] ;
thumbnail_quality = [thumbnail_quality] ;
;
theme_name = uber-responsive ;
[advanced_settings]
images_per_page = [thumbnail_count] ;
;
images_sort_by = natcasesort ;
;
;
;
reverse_sort = false ;
enable_debugging = false ;
|
Это файл, похожий на файл конфигурации UberGallery galleryConfig.ini, но с заполнителями. Он будет использоваться для создания фактического файла конфигурации на лету, когда администратор сохранит форму конфигурации из серверной части.
Наконец, в соответствии с требованиями UberGallery, вам необходимо скопировать system/library/uberGallery/resources/sample.galleryConfig.ini
в system/library/uberGallery/resources/galleryConfig.ini
. Кроме того, убедитесь, что system/library/uberGallery/resources/galleryConfig.ini
и system/library/uberGallery/resources/cache
доступны для записи на веб-сервере.
Далее, создайте файл admin/controller/module/uber_gallery.php
со следующим содержимым.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
<?php
class ControllerModuleUberGallery extends Controller {
private $error = array();
public function index() {
$this->load->language(‘module/uber_gallery’);
$this->load->model(‘extension/module’);
$this->document->setTitle($this->language->get(‘heading_title’));
if (($this->request->server[‘REQUEST_METHOD’] == ‘POST’) && $this->validate()) {
if (!isset($this->request->get[‘module_id’])) {
$this->model_extension_module->addModule(‘uber_gallery’, $this->request->post);
} else {
$this->model_extension_module->editModule($this->request->get[‘module_id’], $this->request->post);
}
// update uber config file
$config_file = implode(«\n»,file(DIR_SYSTEM.’library/uberGallery/resources/oc.galleryConfig.ini’));
$tokens = array(«[cache_expiration]», «[thumbnail_width]», «[thumbnail_height]», «[thumbnail_quality]», «[thumbnail_count]»);
$replacements = array(
$this->request->post[‘thumb_caching’],
$this->request->post[‘thumb_width’],
$this->request->post[‘thumb_height’],
$this->request->post[‘thumb_quality’],
$this->request->post[‘thumb_count’]
);
$save_config_file = str_replace($tokens, $replacements, $config_file);
$fp = fopen(DIR_SYSTEM.’library/uberGallery/resources/galleryConfig.ini’, ‘w’);
@fwrite($fp, $save_config_file, strlen($save_config_file));
$this->session->data[‘success’] = $this->language->get(‘text_success’);
$this->response->redirect($this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’));
}
$data[‘heading_title’] = $this->language->get(‘heading_title’);
$data[‘text_edit’] = $this->language->get(‘text_edit’);
$data[‘text_enabled’] = $this->language->get(‘text_enabled’);
$data[‘text_disabled’] = $this->language->get(‘text_disabled’);
$data[‘entry_name’] = $this->language->get(‘entry_name’);
$data[‘entry_status’] = $this->language->get(‘entry_status’);
$data[‘entry_thumb_caching’] = $this->language->get(‘entry_thumb_caching’);
$data[‘entry_thumb_quality’] = $this->language->get(‘entry_thumb_quality’);
$data[‘entry_thumb_width’] = $this->language->get(‘entry_thumb_width’);
$data[‘entry_thumb_height’] = $this->language->get(‘entry_thumb_height’);
$data[‘entry_thumb_count’] = $this->language->get(‘entry_thumb_count’);
$data[‘entry_enable_module_paging’] = $this->language->get(‘entry_enable_module_paging’);
$data[‘button_save’] = $this->language->get(‘button_save’);
$data[‘button_cancel’] = $this->language->get(‘button_cancel’);
if (isset($this->error[‘warning’])) {
$data[‘error_warning’] = $this->error[‘warning’];
} else {
$data[‘error_warning’] = »;
}
if (isset($this->error[‘error_name’])) {
$data[‘error_name’] = $this->error[‘error_name’];
} else {
$data[‘error_name’] = »;
}
if (isset($this->error[‘error_thumb_width’])) {
$data[‘error_thumb_width’] = $this->error[‘error_thumb_width’];
} else {
$data[‘error_thumb_width’] = »;
}
if (isset($this->error[‘error_thumb_height’])) {
$data[‘error_thumb_height’] = $this->error[‘error_thumb_height’];
} else {
$data[‘error_thumb_height’] = »;
}
if (isset($this->error[‘error_thumb_quality’])) {
$data[‘error_thumb_quality’] = $this->error[‘error_thumb_quality’];
} else {
$data[‘error_thumb_quality’] = »;
}
if (isset($this->error[‘error_thumb_count’])) {
$data[‘error_thumb_count’] = $this->error[‘error_thumb_count’];
} else {
$data[‘error_thumb_count’] = »;
}
$data[‘breadcrumbs’] = array();
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘text_home’),
‘href’ => $this->url->link(‘common/dashboard’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘text_module’),
‘href’ => $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
if (!isset($this->request->get[‘module_id’])) {
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘heading_title’),
‘href’ => $this->url->link(‘module/uber_gallery’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
} else {
$data[‘breadcrumbs’][] = array(
‘text’ => $this->language->get(‘heading_title’),
‘href’ => $this->url->link(‘module/uber_gallery’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’)
);
}
if (!isset($this->request->get[‘module_id’])) {
$data[‘action’] = $this->url->link(‘module/uber_gallery’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);
} else {
$data[‘action’] = $this->url->link(‘module/uber_gallery’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’);
}
$data[‘cancel’] = $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);
if (isset($this->request->get[‘module_id’]) && ($this->request->server[‘REQUEST_METHOD’] != ‘POST’)) {
$module_info = $this->model_extension_module->getModule($this->request->get[‘module_id’]);
}
if (isset($this->request->post[‘name’])) {
$data[‘name’] = $this->request->post[‘name’];
} elseif (!empty($module_info)) {
$data[‘name’] = $module_info[‘name’];
} else {
$data[‘name’] = »;
}
if (isset($this->request->post[‘thumb_width’])) {
$data[‘thumb_width’] = $this->request->post[‘thumb_width’];
} elseif (!empty($module_info)) {
$data[‘thumb_width’] = $module_info[‘thumb_width’];
} else {
$data[‘thumb_width’] = »;
}
if (isset($this->request->post[‘thumb_height’])) {
$data[‘thumb_height’] = $this->request->post[‘thumb_height’];
} elseif (!empty($module_info)) {
$data[‘thumb_height’] = $module_info[‘thumb_height’];
} else {
$data[‘thumb_height’] = »;
}
if (isset($this->request->post[‘thumb_quality’])) {
$data[‘thumb_quality’] = $this->request->post[‘thumb_quality’];
} elseif (!empty($module_info)) {
$data[‘thumb_quality’] = $module_info[‘thumb_quality’];
} else {
$data[‘thumb_quality’] = »;
}
if (isset($this->request->post[‘thumb_count’])) {
$data[‘thumb_count’] = $this->request->post[‘thumb_count’];
} elseif (!empty($module_info)) {
$data[‘thumb_count’] = $module_info[‘thumb_count’];
} else {
$data[‘thumb_count’] = »;
}
if (isset($this->request->post[‘thumb_caching’])) {
$data[‘thumb_caching’] = $this->request->post[‘thumb_caching’];
} elseif (!empty($module_info)) {
$data[‘thumb_caching’] = $module_info[‘thumb_caching’];
} else {
$data[‘thumb_caching’] = »;
}
if (isset($this->request->post[‘enable_module_paging’])) {
$data[‘enable_module_paging’] = $this->request->post[‘enable_module_paging’];
} elseif (!empty($module_info)) {
$data[‘enable_module_paging’] = $module_info[‘enable_module_paging’];
} else {
$data[‘enable_module_paging’] = »;
}
if (isset($this->request->post[‘status’])) {
$data[‘status’] = $this->request->post[‘status’];
} elseif (!empty($module_info)) {
$data[‘status’] = $module_info[‘status’];
} else {
$data[‘status’] = »;
}
$data[‘header’] = $this->load->controller(‘common/header’);
$data[‘column_left’] = $this->load->controller(‘common/column_left’);
$data[‘footer’] = $this->load->controller(‘common/footer’);
$this->response->setOutput($this->load->view(‘module/uber_gallery.tpl’, $data));
}
protected function validate() {
if (!$this->user->hasPermission(‘modify’, ‘module/uber_gallery’)) {
$this->error[‘warning’] = $this->language->get(‘error_permission’);
}
if (!$this->request->post[‘name’]) {
$this->error[‘error_name’] = $this->language->get(‘error_name’);
}
if (!$this->request->post[‘thumb_width’]) {
$this->error[‘error_thumb_width’] = $this->language->get(‘error_thumb_width’);
}
if (!$this->request->post[‘thumb_height’]) {
$this->error[‘error_thumb_height’] = $this->language->get(‘error_thumb_height’);
}
if (!$this->request->post[‘thumb_quality’]) {
$this->error[‘error_thumb_quality’] = $this->language->get(‘error_thumb_quality’);
}
if (!$this->request->post[‘thumb_count’]) {
$this->error[‘error_thumb_count’] = $this->language->get(‘error_thumb_count’);
}
return !$this->error;
}
}
|
Как обычно, вы увидите два стандартных метода в любом файле внутреннего контроллера — метод индекса , который используется для обеспечения стандартной логики, которая имеет дело с хранением значений формы конфигурации, и метод validate , который используется для проверки формы конфигурации ,
Как я уже упоминал в начале статьи, что вы должны быть знакомы с разработкой базовых модулей в OpenCart, мы обсудим код, специфичный для части UberGallery.
Помимо обычного метода индекса, загрузки соответствующих языков и моделей и установки переменных для файла шаблона представления, в нашем методе индекса есть интересный фрагмент кода. Давайте посмотрим на это внимательно.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
// update uber config file
$config_file = implode(«\n»,file(DIR_SYSTEM.’library/uberGallery/resources/oc.galleryConfig.ini’));
$tokens = array(«[cache_expiration]», «[thumbnail_width]», «[thumbnail_height]», «[thumbnail_quality]», «[thumbnail_count]»);
$replacements = array(
$this->request->post[‘thumb_caching’],
$this->request->post[‘thumb_width’],
$this->request->post[‘thumb_height’],
$this->request->post[‘thumb_quality’],
$this->request->post[‘thumb_count’]
);
$save_config_file = str_replace($tokens, $replacements, $config_file);
$fp = fopen(DIR_SYSTEM.’library/uberGallery/resources/galleryConfig.ini’, ‘w’);
@fwrite($fp, $save_config_file, strlen($save_config_file));
|
Здесь мы пытаемся достичь того, что всякий раз, когда администратор сохраняет форму конфигурации UberGallery в бэк-энде, galleryConfig.ini должен создаваться на лету. Напомним, что oc.galleryConfig.ini
мы создали в начале этого раздела, и теперь вы должны понять его хитрость.
Мы извлекаем содержимое system/library/uberGallery/resources/oc.galleryConfig.ini
, заменяя заполнители фактическими значениями и, наконец, сохраняем его как galleryConfig.ini
который перезаписывает существующий файл по умолчанию.
Продвигаясь вперед, создайте файл admin/language/english/module/uber_gallery.php
со следующим содержимым.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?php
// Heading
$_[‘heading_title’] = ‘uberGallery’;
// Text
$_[‘text_module’] = ‘Modules’;
$_[‘text_success’] = ‘Success: You have modified module uberGallery!’;
$_[‘text_edit’] = ‘Edit uberGallery Module’;
// Entry
$_[‘entry_status’] = ‘Status’;
$_[‘entry_name’] = ‘Module Name’;
$_[‘entry_thumb_caching’] = ‘Thumbnail Caching’;
$_[‘entry_thumb_width’] = ‘Thumbnail Width’;
$_[‘entry_thumb_height’] = ‘Thumbnail Height’;
$_[‘entry_thumb_quality’] = ‘Thumbnail Quality’;
$_[‘entry_theme_name’] = ‘Theme Name’;
$_[‘entry_thumb_count’] = ‘Thumbnail Count’;
$_[‘entry_enable_module_paging’] = ‘Module Paging’;
// Error
$_[‘error_permission’] = ‘Warning: You do not have permission to modify specials module!’;
$_[‘error_name’] = ‘Module Name must be between 3 and 64 characters!’;
$_[‘error_thumb_width’] = ‘Please enter thumbnail width!’;
$_[‘error_thumb_height’] = ‘Please enter thumbnail height!’;
$_[‘error_thumb_quality’] = ‘Please enter thumbnail quality!’;
$_[‘error_thumb_count’] = ‘Please enter thumbnail count!’;
|
Ничего необычного — мы просто объявляем языковые переменные в этом файле.
Наконец, мы создадим файл шаблона представления, который содержит XHTML для нашей пользовательской формы конфигурации. Создайте файл admin/view/template/module/uber_gallery.tpl
со следующим содержимым.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
<?php echo $header;
<div id=»content»>
<div class=»page-header»>
<div class=»container-fluid»>
<div class=»pull-right»>
<button type=»submit» form=»form-uber-gallery» data-toggle=»tooltip» title=»<?php echo $button_save; ?>» class=»btn btn-primary»><i class=»fa fa-save»></i></button>
<a href=»<?php echo $cancel; ?>» data-toggle=»tooltip» title=»<?php echo $button_cancel; ?>» class=»btn btn-default»><i class=»fa fa-reply»></i></a></div>
<h1><?php echo $heading_title;
<ul class=»breadcrumb»>
<?php foreach ($breadcrumbs as $breadcrumb) { ?>
<li><a href=»<?php echo $breadcrumb[‘href’]; ?>»><?php echo $breadcrumb[‘text’];
<?php } ?>
</ul>
</div>
</div>
<div class=»container-fluid»>
<?php if ($error_warning) { ?>
<div class=»alert alert-danger»><i class=»fa fa-exclamation-circle»></i> <?php echo $error_warning;
<button type=»button» class=»close» data-dismiss=»alert»>×</button>
</div>
<?php } ?>
<div class=»panel panel-default»>
<div class=»panel-heading»>
<h3 class=»panel-title»><i class=»fa fa-pencil»></i> <?php echo $text_edit;
</div>
<div class=»panel-body»>
<form action=»<?php echo $action; ?>» method=»post» enctype=»multipart/form-data» id=»form-special» class=»form-horizontal»>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-name»><?php echo $entry_name;
<div class=»col-sm-10″>
<input type=»text» name=»name» value=»<?php echo $name; ?>» placeholder=»<?php echo $entry_name; ?>» id=»input-name» class=»form-control» />
<?php if ($error_name) { ?>
<div class=»text-danger»><?php echo $error_name;
<?php } ?>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-thumb-caching»><?php echo $entry_thumb_caching;
<div class=»col-sm-10″>
<select name=»thumb_caching» id=»input-thumb-caching» class=»form-control»>
<?php if ($thumb_caching) { ?>
<option value=»-1″ selected=»selected»><?php echo $text_enabled;
<option value=»0″><?php echo $text_disabled;
<?php } else { ?>
<option value=»-1″><?php echo $text_enabled;
<option value=»0″ selected=»selected»><?php echo $text_disabled;
<?php } ?>
</select>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-thumb-width»><?php echo $entry_thumb_width;
<div class=»col-sm-10″>
<input type=»text» name=»thumb_width» value=»<?php echo $thumb_width; ?>» placeholder=»<?php echo $entry_thumb_width; ?>» id=»input-thumb-width» class=»form-control» />
<?php if ($error_thumb_width) { ?>
<div class=»text-danger»><?php echo $error_thumb_width;
<?php } ?>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-thumb-height»><?php echo $entry_thumb_height;
<div class=»col-sm-10″>
<input type=»text» name=»thumb_height» value=»<?php echo $thumb_height; ?>» placeholder=»<?php echo $entry_thumb_height; ?>» id=»input-thumb-height» class=»form-control» />
<?php if ($error_thumb_height) { ?>
<div class=»text-danger»><?php echo $error_thumb_height;
<?php } ?>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-thumb-quality»><?php echo $entry_thumb_quality;
<div class=»col-sm-10″>
<input type=»text» name=»thumb_quality» value=»<?php echo $thumb_quality; ?>» placeholder=»<?php echo $entry_thumb_quality; ?>» id=»input-thumb-quality» class=»form-control» /> (between 1-100)
<?php if ($error_thumb_quality) { ?>
<div class=»text-danger»><?php echo $error_thumb_quality;
<?php } ?>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-thumb-count»><?php echo $entry_thumb_count;
<div class=»col-sm-10″>
<input type=»text» name=»thumb_count» value=»<?php echo $thumb_count; ?>» placeholder=»<?php echo $entry_thumb_count; ?>» id=»input-thumb-count» class=»form-control» />
<?php if ($error_thumb_count) { ?>
<div class=»text-danger»><?php echo $error_thumb_count;
<?php } ?>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-enable-module-paging»><?php echo $entry_enable_module_paging;
<div class=»col-sm-10″>
<select name=»enable_module_paging» id=»input-enable-module-paging» class=»form-control»>
<?php if ($enable_module_paging) { ?>
<option value=»1″ selected=»selected»><?php echo $text_enabled;
<option value=»0″><?php echo $text_disabled;
<?php } else { ?>
<option value=»1″><?php echo $text_enabled;
<option value=»0″ selected=»selected»><?php echo $text_disabled;
<?php } ?>
</select>
</div>
</div>
<div class=»form-group»>
<label class=»col-sm-2 control-label» for=»input-status»><?php echo $entry_status;
<div class=»col-sm-10″>
<select name=»status» id=»input-status» class=»form-control»>
<?php if ($status) { ?>
<option value=»1″ selected=»selected»><?php echo $text_enabled;
<option value=»0″><?php echo $text_disabled;
<?php } else { ?>
<option value=»1″><?php echo $text_enabled;
<option value=»0″ selected=»selected»><?php echo $text_disabled;
<?php } ?>
</select>
</div>
</form>
</div>
</div>
</div>
</div>
<?php echo $footer;
|
Итак, вот и все, что касается настройки внутреннего файла.
Проверьте форму конфигурации
Перейдите на задний план и перейдите к Расширения> Модули . Установите наш недавно созданный модуль uberGallery и отредактируйте его, чтобы открыть форму конфигурации.
Заполните необходимые значения и сохраните форму! Конечно, он сохранит настройки модуля в базе данных, но в дополнение к этому он также сгенерирует новый galleryConfig.ini
! Откройте system/library/uberGallery/resources/galleryConfig.ini
, и он должен отражать значения параметров в полях формы конфигурации.
Итак, мы только что создали механизм для создания galleryConfig.ini
на лету, используя форму конфигурации! Он будет использоваться во внешнем интерфейсе, когда мы включим модуль для отображения галереи.
Итак, вот и все для сегодняшней статьи. Я скоро вернусь со следующей частью этой серии.
Вывод
В этой первой части мы рассмотрели настройку внутреннего файла для модуля UberGallery. В следующей части мы рассмотрим его внешний интерфейс. Для любых запросов используйте ленту комментариев ниже!