Page MenuHomePhabricator

D15050.id36348.diff
No OneTemporary

D15050.id36348.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2314,6 +2314,8 @@
'PhabricatorFileinfoSetupCheck' => 'applications/config/check/PhabricatorFileinfoSetupCheck.php',
'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php',
'PhabricatorFilesApplicationStorageEnginePanel' => 'applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php',
+ 'PhabricatorFilesBuiltinFile' => 'applications/files/builtin/PhabricatorFilesBuiltinFile.php',
+ 'PhabricatorFilesComposeIconBuiltinFile' => 'applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php',
'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php',
'PhabricatorFilesManagementCatWorkflow' => 'applications/files/management/PhabricatorFilesManagementCatWorkflow.php',
'PhabricatorFilesManagementCompactWorkflow' => 'applications/files/management/PhabricatorFilesManagementCompactWorkflow.php',
@@ -2322,6 +2324,7 @@
'PhabricatorFilesManagementPurgeWorkflow' => 'applications/files/management/PhabricatorFilesManagementPurgeWorkflow.php',
'PhabricatorFilesManagementRebuildWorkflow' => 'applications/files/management/PhabricatorFilesManagementRebuildWorkflow.php',
'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php',
+ 'PhabricatorFilesOnDiskBuiltinFile' => 'applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php',
'PhabricatorFilesOutboundRequestAction' => 'applications/files/action/PhabricatorFilesOutboundRequestAction.php',
'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php',
'PhabricatorFlagAddFlagHeraldAction' => 'applications/flag/herald/PhabricatorFlagAddFlagHeraldAction.php',
@@ -6610,6 +6613,8 @@
'PhabricatorFileinfoSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorFilesApplication' => 'PhabricatorApplication',
'PhabricatorFilesApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel',
+ 'PhabricatorFilesBuiltinFile' => 'Phobject',
+ 'PhabricatorFilesComposeIconBuiltinFile' => 'PhabricatorFilesBuiltinFile',
'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorFilesManagementCatWorkflow' => 'PhabricatorFilesManagementWorkflow',
'PhabricatorFilesManagementCompactWorkflow' => 'PhabricatorFilesManagementWorkflow',
@@ -6618,6 +6623,7 @@
'PhabricatorFilesManagementPurgeWorkflow' => 'PhabricatorFilesManagementWorkflow',
'PhabricatorFilesManagementRebuildWorkflow' => 'PhabricatorFilesManagementWorkflow',
'PhabricatorFilesManagementWorkflow' => 'PhabricatorManagementWorkflow',
+ 'PhabricatorFilesOnDiskBuiltinFile' => 'PhabricatorFilesBuiltinFile',
'PhabricatorFilesOutboundRequestAction' => 'PhabricatorSystemAction',
'PhabricatorFlag' => array(
'PhabricatorFlagDAO',
diff --git a/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php
@@ -0,0 +1,9 @@
+<?php
+
+abstract class PhabricatorFilesBuiltinFile extends Phobject {
+
+ abstract public function getBuiltinFileKey();
+ abstract public function getBuiltinDisplayName();
+ abstract public function loadBuiltinFileData();
+
+}
diff --git a/src/applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php
@@ -0,0 +1,235 @@
+<?php
+
+final class PhabricatorFilesComposeIconBuiltinFile
+ extends PhabricatorFilesBuiltinFile {
+
+ private $icon;
+ private $color;
+
+ public function setIcon($icon) {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ public function getIcon() {
+ return $this->icon;
+ }
+
+ public function setColor($color) {
+ $this->color = $color;
+ return $this;
+ }
+
+ public function getColor() {
+ return $this->color;
+ }
+
+ public function getBuiltinFileKey() {
+ $icon = $this->getIcon();
+ $color = $this->getColor();
+ $desc = "compose(icon={$icon}, color={$color})";
+ $hash = PhabricatorHash::digestToLength($desc, 40);
+ return "builtin:{$hash}";
+ }
+
+ public function getBuiltinDisplayName() {
+ $icon = $this->getIcon();
+ $color = $this->getColor();
+ return "{$icon}-{$color}.png";
+ }
+
+ public function loadBuiltinFileData() {
+ return $this->composeImage($this->getColor(), $this->getIcon());
+ }
+
+ public static function getAllIcons() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $root = $root.'/resources/sprite/projects_2x/';
+
+ $quips = self::getIconQuips();
+
+ $map = array();
+ $list = Filesystem::listDirectory($root, $include_hidden = false);
+ foreach ($list as $file) {
+ $short = preg_replace('/\.png$/', '', $file);
+
+ $map[$short] = array(
+ 'path' => $root.$file,
+ 'quip' => idx($quips, $short, $short),
+ );
+ }
+
+ return $map;
+ }
+
+ public static function getAllColors() {
+ $colors = id(new CelerityResourceTransformer())
+ ->getCSSVariableMap();
+
+ $colors = array_select_keys(
+ $colors,
+ array(
+ 'red',
+ 'orange',
+ 'yellow',
+ 'green',
+ 'blue',
+ 'sky',
+ 'indigo',
+ 'violet',
+ 'pink',
+ 'charcoal',
+ 'backdrop',
+ ));
+
+ $quips = self::getColorQuips();
+
+ $map = array();
+ foreach ($colors as $name => $color) {
+ $map[$name] = array(
+ 'color' => $color,
+ 'quip' => idx($quips, $name, $name),
+ );
+ }
+
+ return $map;
+ }
+
+ private function composeImage($color, $icon) {
+ $color_map = self::getAllColors();
+ $color = idx($color_map, $color);
+ if (!$color) {
+ $fallback = 'backdrop';
+ $color = idx($color_map, $fallback);
+ if (!$color) {
+ throw new Exception(
+ pht(
+ 'Fallback compose color ("%s") does not exist!',
+ $fallback));
+ }
+ }
+
+ $color_hex = idx($color, 'color');
+ $color_const = hexdec(trim($color_hex, '#'));
+
+ $icon_map = self::getAllIcons();
+ $icon = idx($icon_map, $icon);
+ if (!$icon) {
+ $fallback = 'fa-umbrella';
+ $icon = idx($icon_map, $fallback);
+ if (!$icon) {
+ throw new Exception(
+ pht(
+ 'Fallback compose icon ("%s") does not exist!',
+ $fallback));
+ }
+ }
+
+ $path = idx($icon, 'path');
+ $data = Filesystem::readFile($path);
+
+ $icon_img = imagecreatefromstring($data);
+
+ $canvas = imagecreatetruecolor(100, 100);
+ imagefill($canvas, 0, 0, $color_const);
+ imagecopy($canvas, $icon_img, 0, 0, 0, 0, 100, 100);
+
+ return PhabricatorImageTransformer::saveImageDataInAnyFormat(
+ $canvas,
+ 'image/png');
+ }
+
+ private static function getIconQuips() {
+ return array(
+ '8ball' => pht('Take a Risk'),
+ 'alien' => pht('Foreign Interface'),
+ 'announce' => pht('Louder is Better'),
+ 'art' => pht('Unique Snowflake'),
+ 'award' => pht('Shooting Star'),
+ 'bacon' => pht('Healthy Vegetables'),
+ 'bandaid' => pht('Durable Infrastructure'),
+ 'beer' => pht('Healthy Vegetable Juice'),
+ 'bomb' => pht('Imminent Success'),
+ 'briefcase' => pht('Adventure Pack'),
+ 'bug' => pht('Costumed Egg'),
+ 'calendar' => pht('Everyone Loves Meetings'),
+ 'cloud' => pht('Water Cycle'),
+ 'coffee' => pht('Half-Whip Nonfat Soy Latte'),
+ 'creditcard' => pht('Expense It'),
+ 'death' => pht('Calcium Promotes Bone Health'),
+ 'desktop' => pht('Magical Portal'),
+ 'dropbox' => pht('Cardboard Box'),
+ 'education' => pht('Debt'),
+ 'experimental' => pht('CAUTION: Dangerous Chemicals'),
+ 'facebook' => pht('Popular Social Network'),
+ 'facility' => pht('Pollution Solves Problems'),
+ 'film' => pht('Actual Physical Film'),
+ 'forked' => pht('You Can\'t Eat Soup'),
+ 'games' => pht('Serious Business'),
+ 'ghost' => pht('Haunted'),
+ 'gift' => pht('Surprise!'),
+ 'globe' => pht('Scanner Sweep'),
+ 'golf' => pht('Business Meeting'),
+ 'heart' => pht('Undergoing a Major Surgery'),
+ 'intergalactic' => pht('Jupiter'),
+ 'lock' => pht('Extremely Secret'),
+ 'mail' => pht('Oragami'),
+ 'martini' => pht('Healthy Olive Drink'),
+ 'medical' => pht('Medic!'),
+ 'mobile' => pht('Cellular Telephone'),
+ 'music' => pht("\xE2\x99\xAB"),
+ 'news' => pht('Actual Physical Newspaper'),
+ 'orgchart' => pht('It\'s Good to be King'),
+ 'peoples' => pht('Angel and Devil'),
+ 'piechart' => pht('Actual Physical Pie'),
+ 'poison' => pht('Healthy Bone Juice'),
+ 'putabirdonit' => pht('Put a Bird On It'),
+ 'radiate' => pht('Radiant Beauty'),
+ 'savings' => pht('Oink Oink'),
+ 'search' => pht('Sleuthing'),
+ 'shield' => pht('Royal Crest'),
+ 'speed' => pht('Slow and Steady'),
+ 'sprint' => pht('Fire Exit'),
+ 'star' => pht('The More You Know'),
+ 'storage' => pht('Stack of Pancakes'),
+ 'tablet' => pht('Cellular Telephone For Giants'),
+ 'travel' => pht('Pretty Clearly an Airplane'),
+ 'twitter' => pht('Bird Stencil'),
+ 'warning' => pht('No Caution Required, Everything Looks Safe'),
+ 'whale' => pht('Friendly Walrus'),
+ 'fa-flask' => pht('Experimental'),
+ 'fa-briefcase' => pht('Briefcase'),
+ 'fa-bug' => pht('Bug'),
+ 'fa-building' => pht('Company'),
+ 'fa-calendar' => pht('Deadline'),
+ 'fa-cloud' => pht('The Cloud'),
+ 'fa-credit-card' => pht('Accounting'),
+ 'fa-envelope' => pht('Communication'),
+ 'fa-flag-checkered' => pht('Goal'),
+ 'fa-folder' => pht('Folder'),
+ 'fa-group' => pht('Team'),
+ 'fa-lock' => pht('Policy'),
+ 'fa-tags' => pht('Tag'),
+ 'fa-trash-o' => pht('Garbage'),
+ 'fa-truck' => pht('Release'),
+ 'fa-umbrella' => pht('An Umbrella'),
+ );
+ }
+
+ private static function getColorQuips() {
+ return array(
+ 'red' => pht('Verbillion'),
+ 'orange' => pht('Navel Orange'),
+ 'yellow' => pht('Prim Goldenrod'),
+ 'green' => pht('Lustrous Verdant'),
+ 'blue' => pht('Tropical Deep'),
+ 'sky' => pht('Wide Open Sky'),
+ 'indigo' => pht('Pleated Khaki'),
+ 'violet' => pht('Aged Merlot'),
+ 'pink' => pht('Easter Bunny'),
+ 'charcoal' => pht('Gemstone'),
+ 'backdrop' => pht('Driven Snow'),
+ );
+ }
+
+}
diff --git a/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php
@@ -0,0 +1,56 @@
+<?php
+
+final class PhabricatorFilesOnDiskBuiltinFile
+ extends PhabricatorFilesBuiltinFile {
+
+ private $name;
+
+ public function setName($name) {
+ $this->name = $name;
+ return $this;
+ }
+
+ public function getName() {
+ if ($this->name === null) {
+ throw new PhutilInvalidStateException('setName');
+ }
+
+ return $this->name;
+ }
+
+ public function getBuiltinDisplayName() {
+ return $this->getName();
+ }
+
+ public function getBuiltinFileKey() {
+ $name = $this->getName();
+ $desc = "disk(name={$name})";
+ $hash = PhabricatorHash::digestToLength($desc, 40);
+ return "builtin:{$hash}";
+ }
+
+ public function loadBuiltinFileData() {
+ $name = $this->getName();
+
+ $available = $this->getAllBuiltinFiles();
+ if (empty($available[$name])) {
+ throw new Exception(pht('Builtin "%s" does not exist!', $name));
+ }
+
+ return Filesystem::readFile($available[$name]);
+ }
+
+ private function getAllBuiltinFiles() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $root = $root.'/resources/builtin/';
+
+ $map = array();
+ $list = Filesystem::listDirectory($root, $include_hidden = false);
+ foreach ($list as $file) {
+ $map[$file] = $root.$file;
+ }
+
+ return $map;
+ }
+
+}
diff --git a/src/applications/files/controller/PhabricatorFileComposeController.php b/src/applications/files/controller/PhabricatorFileComposeController.php
--- a/src/applications/files/controller/PhabricatorFileComposeController.php
+++ b/src/applications/files/controller/PhabricatorFileComposeController.php
@@ -6,21 +6,8 @@
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
- $colors = array(
- 'red' => pht('Verbillion'),
- 'orange' => pht('Navel Orange'),
- 'yellow' => pht('Prim Goldenrod'),
- 'green' => pht('Lustrous Verdant'),
- 'blue' => pht('Tropical Deep'),
- 'sky' => pht('Wide Open Sky'),
- 'indigo' => pht('Pleated Khaki'),
- 'violet' => pht('Aged Merlot'),
- 'pink' => pht('Easter Bunny'),
- 'charcoal' => pht('Gemstone'),
- 'backdrop' => pht('Driven Snow'),
- );
-
- $manifest = PHUIIconView::getSheetManifest(PHUIIconView::SPRITE_PROJECTS);
+ $color_map = PhabricatorFilesComposeIconBuiltinFile::getAllColors();
+ $icon_map = $this->getIconMap();
if ($request->isFormPost()) {
$project_phid = $request->getStr('projectPHID');
@@ -37,36 +24,21 @@
if (!$project) {
return new Aphront404Response();
}
- $icon = $project->getIcon();
- $color = $project->getColor();
- switch ($color) {
- case 'grey':
- $color = 'charcoal';
- break;
- case 'checkered':
- $color = 'backdrop';
- break;
- }
- } else {
- $icon = $request->getStr('icon');
- $color = $request->getStr('color');
}
- if (!isset($colors[$color]) || !isset($manifest['projects-'.$icon])) {
- return new Aphront404Response();
- }
-
- $root = dirname(phutil_get_library_root('phabricator'));
- $icon_file = $root.'/resources/sprite/projects_2x/'.$icon.'.png';
- $icon_data = Filesystem::readFile($icon_file);
+ $icon = $request->getStr('icon');
+ $color = $request->getStr('color');
+ $composer = id(new PhabricatorFilesComposeIconBuiltinFile())
+ ->setIcon($icon)
+ ->setColor($color);
- $data = $this->composeImage($color, $icon_data);
+ $data = $composer->loadBuiltinFileData();
$file = PhabricatorFile::buildFromFileDataOrHash(
$data,
array(
- 'name' => 'project.png',
+ 'name' => $composer->getBuiltinDisplayName(),
'profile' => true,
'canCDN' => true,
));
@@ -97,14 +69,15 @@
}
}
- $value_color = head_key($colors);
- $value_icon = head_key($manifest);
- $value_icon = substr($value_icon, strlen('projects-'));
+ $value_color = head_key($color_map);
+ $value_icon = head_key($icon_map);
require_celerity_resource('people-profile-css');
$buttons = array();
- foreach ($colors as $color => $name) {
+ foreach ($color_map as $color => $info) {
+ $quip = idx($info, 'quip');
+
$buttons[] = javelin_tag(
'button',
array(
@@ -113,116 +86,17 @@
'style' => 'margin: 0 8px 8px 0',
'meta' => array(
'color' => $color,
- 'tip' => $name,
+ 'tip' => $quip,
),
),
id(new PHUIIconView())
->addClass('compose-background-'.$color));
}
- $sort_these_first = array(
- 'projects-fa-briefcase',
- 'projects-fa-tags',
- 'projects-fa-folder',
- 'projects-fa-group',
- 'projects-fa-bug',
- 'projects-fa-trash-o',
- 'projects-fa-calendar',
- 'projects-fa-flag-checkered',
- 'projects-fa-envelope',
- 'projects-fa-truck',
- 'projects-fa-lock',
- 'projects-fa-umbrella',
- 'projects-fa-cloud',
- 'projects-fa-building',
- 'projects-fa-credit-card',
- 'projects-fa-flask',
- );
-
- $manifest = array_select_keys(
- $manifest,
- $sort_these_first)
- + $manifest;
$icons = array();
-
- $icon_quips = array(
- '8ball' => pht('Take a Risk'),
- 'alien' => pht('Foreign Interface'),
- 'announce' => pht('Louder is Better'),
- 'art' => pht('Unique Snowflake'),
- 'award' => pht('Shooting Star'),
- 'bacon' => pht('Healthy Vegetables'),
- 'bandaid' => pht('Durable Infrastructure'),
- 'beer' => pht('Healthy Vegetable Juice'),
- 'bomb' => pht('Imminent Success'),
- 'briefcase' => pht('Adventure Pack'),
- 'bug' => pht('Costumed Egg'),
- 'calendar' => pht('Everyone Loves Meetings'),
- 'cloud' => pht('Water Cycle'),
- 'coffee' => pht('Half-Whip Nonfat Soy Latte'),
- 'creditcard' => pht('Expense It'),
- 'death' => pht('Calcium Promotes Bone Health'),
- 'desktop' => pht('Magical Portal'),
- 'dropbox' => pht('Cardboard Box'),
- 'education' => pht('Debt'),
- 'experimental' => pht('CAUTION: Dangerous Chemicals'),
- 'facebook' => pht('Popular Social Network'),
- 'facility' => pht('Pollution Solves Problems'),
- 'film' => pht('Actual Physical Film'),
- 'forked' => pht('You Can\'t Eat Soup'),
- 'games' => pht('Serious Business'),
- 'ghost' => pht('Haunted'),
- 'gift' => pht('Surprise!'),
- 'globe' => pht('Scanner Sweep'),
- 'golf' => pht('Business Meeting'),
- 'heart' => pht('Undergoing a Major Surgery'),
- 'intergalactic' => pht('Jupiter'),
- 'lock' => pht('Extremely Secret'),
- 'mail' => pht('Oragami'),
- 'martini' => pht('Healthy Olive Drink'),
- 'medical' => pht('Medic!'),
- 'mobile' => pht('Cellular Telephone'),
- 'music' => pht("\xE2\x99\xAB"),
- 'news' => pht('Actual Physical Newspaper'),
- 'orgchart' => pht('It\'s Good to be King'),
- 'peoples' => pht('Angel and Devil'),
- 'piechart' => pht('Actual Physical Pie'),
- 'poison' => pht('Healthy Bone Juice'),
- 'putabirdonit' => pht('Put a Bird On It'),
- 'radiate' => pht('Radiant Beauty'),
- 'savings' => pht('Oink Oink'),
- 'search' => pht('Sleuthing'),
- 'shield' => pht('Royal Crest'),
- 'speed' => pht('Slow and Steady'),
- 'sprint' => pht('Fire Exit'),
- 'star' => pht('The More You Know'),
- 'storage' => pht('Stack of Pancakes'),
- 'tablet' => pht('Cellular Telephone For Giants'),
- 'travel' => pht('Pretty Clearly an Airplane'),
- 'twitter' => pht('Bird Stencil'),
- 'warning' => pht('No Caution Required, Everything Looks Safe'),
- 'whale' => pht('Friendly Walrus'),
- 'fa-flask' => pht('Experimental'),
- 'fa-briefcase' => pht('Briefcase'),
- 'fa-bug' => pht('Bug'),
- 'fa-building' => pht('Company'),
- 'fa-calendar' => pht('Deadline'),
- 'fa-cloud' => pht('The Cloud'),
- 'fa-credit-card' => pht('Accounting'),
- 'fa-envelope' => pht('Communication'),
- 'fa-flag-checkered' => pht('Goal'),
- 'fa-folder' => pht('Folder'),
- 'fa-group' => pht('Team'),
- 'fa-lock' => pht('Policy'),
- 'fa-tags' => pht('Tag'),
- 'fa-trash-o' => pht('Garbage'),
- 'fa-truck' => pht('Release'),
- 'fa-umbrella' => pht('An Umbrella'),
- );
-
- foreach ($manifest as $icon => $spec) {
- $icon = substr($icon, strlen('projects-'));
+ foreach ($icon_map as $icon => $spec) {
+ $quip = idx($spec, 'quip');
$icons[] = javelin_tag(
'button',
@@ -232,7 +106,7 @@
'style' => 'margin: 0 8px 8px 0',
'meta' => array(
'icon' => $icon,
- 'tip' => idx($icon_quips, $icon, $icon),
+ 'tip' => $quip,
),
),
id(new PHUIIconView())
@@ -318,23 +192,31 @@
return id(new AphrontDialogResponse())->setDialog($dialog);
}
- private function composeImage($color, $icon_data) {
- $icon_img = imagecreatefromstring($icon_data);
-
- $map = id(new CelerityResourceTransformer())
- ->getCSSVariableMap();
-
- $color_string = idx($map, $color, '#ff00ff');
- $color_const = hexdec(trim($color_string, '#'));
-
- $canvas = imagecreatetruecolor(100, 100);
- imagefill($canvas, 0, 0, $color_const);
+ private function getIconMap() {
+ $icon_map = PhabricatorFilesComposeIconBuiltinFile::getAllIcons();
+
+ $first = array(
+ 'fa-briefcase',
+ 'fa-tags',
+ 'fa-folder',
+ 'fa-group',
+ 'fa-bug',
+ 'fa-trash-o',
+ 'fa-calendar',
+ 'fa-flag-checkered',
+ 'fa-envelope',
+ 'fa-truck',
+ 'fa-lock',
+ 'fa-umbrella',
+ 'fa-cloud',
+ 'fa-building',
+ 'fa-credit-card',
+ 'fa-flask',
+ );
- imagecopy($canvas, $icon_img, 0, 0, 0, 0, 100, 100);
+ $icon_map = array_select_keys($icon_map, $first) + $icon_map;
- return PhabricatorImageTransformer::saveImageDataInAnyFormat(
- $canvas,
- 'image/png');
+ return $icon_map;
}
}
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -961,16 +961,18 @@
* Builtins are located in `resources/builtin/` and identified by their
* name.
*
- * @param PhabricatorUser Viewing user.
- * @param list<string> List of builtin file names.
- * @return dict<string, PhabricatorFile> Dictionary of named builtins.
+ * @param PhabricatorUser Viewing user.
+ * @param list<PhabricatorFilesBuiltinFile> List of builtin file specs.
+ * @return dict<string, PhabricatorFile> Dictionary of named builtins.
*/
- public static function loadBuiltins(PhabricatorUser $user, array $names) {
+ public static function loadBuiltins(PhabricatorUser $user, array $builtins) {
+ $builtins = mpull($builtins, null, 'getBuiltinFileKey');
+
$specs = array();
- foreach ($names as $name) {
+ foreach ($builtins as $key => $buitin) {
$specs[] = array(
'originalPHID' => PhabricatorPHIDConstants::PHID_VOID,
- 'transform' => 'builtin:'.$name,
+ 'transform' => $key,
);
}
@@ -981,41 +983,34 @@
->withTransforms($specs)
->execute();
- $files = mpull($files, null, 'getName');
-
- $root = dirname(phutil_get_library_root('phabricator'));
- $root = $root.'/resources/builtin/';
+ $results = array();
+ foreach ($files as $file) {
+ $builtin_key = $file->getBuiltinName();
+ if ($builtin_key !== null) {
+ $results[$builtin_key] = $file;
+ }
+ }
$build = array();
- foreach ($names as $name) {
- if (isset($files[$name])) {
+ foreach ($builtins as $key => $builtin) {
+ if (isset($results[$key])) {
continue;
}
- // This is just a sanity check to prevent loading arbitrary files.
- if (basename($name) != $name) {
- throw new Exception(pht("Invalid builtin name '%s'!", $name));
- }
-
- $path = $root.$name;
-
- if (!Filesystem::pathExists($path)) {
- throw new Exception(pht("Builtin '%s' does not exist!", $path));
- }
+ $data = $builtin->loadBuiltinFileData();
- $data = Filesystem::readFile($path);
$params = array(
- 'name' => $name,
+ 'name' => $builtin->getBuiltinDisplayName(),
'ttl' => time() + (60 * 60 * 24 * 7),
'canCDN' => true,
- 'builtin' => $name,
+ 'builtin' => $key,
);
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$file = self::newFromFileData($data, $params);
$xform = id(new PhabricatorTransformedFile())
->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID)
- ->setTransform('builtin:'.$name)
+ ->setTransform($key)
->setTransformedPHID($file->getPHID())
->save();
unset($unguarded);
@@ -1023,10 +1018,10 @@
$file->attachObjectPHIDs(array());
$file->attachObjects(array());
- $files[$name] = $file;
+ $results[$key] = $file;
}
- return $files;
+ return $results;
}
@@ -1038,7 +1033,12 @@
* @return PhabricatorFile Corresponding builtin file.
*/
public static function loadBuiltin(PhabricatorUser $user, $name) {
- return idx(self::loadBuiltins($user, array($name)), $name);
+ $builtin = id(new PhabricatorFilesOnDiskBuiltinFile())
+ ->setName($name);
+
+ $key = $builtin->getBuiltinFileKey();
+
+ return idx(self::loadBuiltins($user, array($builtin)), $key);
}
public function getObjects() {
diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php
--- a/src/applications/pholio/view/PholioMockImagesView.php
+++ b/src/applications/pholio/view/PholioMockImagesView.php
@@ -68,11 +68,9 @@
// TODO: We could maybe do a better job with tailoring this, which is the
// image shown on the review stage.
- $default_name = 'image-100x100.png';
- $builtins = PhabricatorFile::loadBuiltins(
- $this->getUser(),
- array($default_name));
- $default = $builtins[$default_name];
+ $viewer = $this->getUser();
+
+ $default = PhabricatorFile::loadBuiltin($viewer, 'image-100x100.png');
$engine = id(new PhabricatorMarkupEngine())
->setViewer($this->getUser());
diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
--- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php
+++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
@@ -123,7 +123,7 @@
$images[PhabricatorPHIDConstants::PHID_VOID] = array(
'uri' => $default_image->getBestURI(),
- 'tip' => pht('Default Picture'),
+ 'tip' => pht('No Picture'),
);
require_celerity_resource('people-profile-css');
@@ -181,7 +181,11 @@
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Use Picture'))
- ->setValue($buttons));
+ ->setValue(
+ array(
+ $this->renderDefaultForm($project),
+ $buttons,
+ )));
$launch_id = celerity_generate_unique_node_id();
$input_id = celerity_generate_unique_node_id();
@@ -226,38 +230,6 @@
->setLabel(pht('Quick Create'))
->setValue($compose_form));
- $default_button = javelin_tag(
- 'button',
- array(
- 'class' => 'grey',
- ),
- pht('Use Project Icon'));
-
- $default_input = javelin_tag(
- 'input',
- array(
- 'type' => 'hidden',
- 'name' => 'projectPHID',
- 'value' => $project->getPHID(),
- ));
-
- $default_form = phabricator_form(
- $viewer,
- array(
- 'class' => 'profile-image-form',
- 'method' => 'POST',
- 'action' => '/file/compose/',
- ),
- array(
- $default_input,
- $default_button,
- ));
-
- $form->appendChild(
- id(new AphrontFormMarkupControl())
- ->setLabel(pht('Use Default'))
- ->setValue($default_form));
-
$upload_form = id(new AphrontFormView())
->setUser($viewer)
->setEncType('multipart/form-data')
@@ -294,4 +266,69 @@
$upload_box,
));
}
+
+ private function renderDefaultForm(PhabricatorProject $project) {
+ $viewer = $this->getViewer();
+ $compose_color = $project->getDisplayIconComposeColor();
+ $compose_icon = $project->getDisplayIconComposeIcon();
+
+ $default_builtin = id(new PhabricatorFilesComposeIconBuiltinFile())
+ ->setColor($compose_color)
+ ->setIcon($compose_icon);
+
+ $file_builtins = PhabricatorFile::loadBuiltins(
+ $viewer,
+ array($default_builtin));
+
+ $file_builtin = head($file_builtins);
+
+ $default_button = javelin_tag(
+ 'button',
+ array(
+ 'class' => 'grey profile-image-button',
+ 'sigil' => 'has-tooltip',
+ 'meta' => array(
+ 'tip' => pht('Use Icon and Color'),
+ 'size' => 300,
+ ),
+ ),
+ phutil_tag(
+ 'img',
+ array(
+ 'height' => 50,
+ 'width' => 50,
+ 'src' => $file_builtin->getBestURI(),
+ )));
+
+ $inputs = array(
+ 'projectPHID' => $project->getPHID(),
+ 'icon' => $compose_icon,
+ 'color' => $compose_color,
+ );
+
+ foreach ($inputs as $key => $value) {
+ $inputs[$key] = javelin_tag(
+ 'input',
+ array(
+ 'type' => 'hidden',
+ 'name' => $key,
+ 'value' => $value,
+ ));
+ }
+
+ $default_form = phabricator_form(
+ $viewer,
+ array(
+ 'class' => 'profile-image-form',
+ 'method' => 'POST',
+ 'action' => '/file/compose/',
+ ),
+ array(
+ $inputs,
+ $default_button,
+ ));
+
+ return $default_form;
+ }
+
}
diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
--- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
+++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
@@ -713,6 +713,10 @@
}
}
+ if ($this->getIsNewObject()) {
+ $this->setDefaultProfilePicture($object);
+ }
+
// TODO: We should dump an informational transaction onto the parent
// project to show that we created the sub-thing.
@@ -886,5 +890,31 @@
return $results;
}
+ private function setDefaultProfilePicture(PhabricatorProject $project) {
+ if ($project->isMilestone()) {
+ return;
+ }
+
+ $compose_color = $project->getDisplayIconComposeColor();
+ $compose_icon = $project->getDisplayIconComposeIcon();
+
+ $builtin = id(new PhabricatorFilesComposeIconBuiltinFile())
+ ->setColor($compose_color)
+ ->setIcon($compose_icon);
+
+ $data = $builtin->loadBuiltinFileData();
+
+ $file = PhabricatorFile::newFromFileData(
+ $data,
+ array(
+ 'name' => $builtin->getBuiltinDisplayName(),
+ 'profile' => true,
+ 'canCDN' => true,
+ ));
+
+ $project
+ ->setProfileImagePHID($file->getPHID())
+ ->save();
+ }
}
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -519,6 +519,23 @@
return $this->getColor();
}
+ public function getDisplayIconComposeIcon() {
+ $icon = $this->getDisplayIconIcon();
+ return $icon;
+ }
+
+ public function getDisplayIconComposeColor() {
+ $color = $this->getDisplayColor();
+
+ $map = array(
+ 'grey' => 'charcoal',
+ 'checkered' => 'backdrop',
+ );
+
+ return idx($map, $color, $color);
+ }
+
+
/* -( PhabricatorSubscribableInterface )----------------------------------- */

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 23, 2:25 AM (18 h, 39 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7035332
Default Alt Text
D15050.id36348.diff (30 KB)

Event Timeline