Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make info block visibility configurable #1404

Merged
merged 14 commits into from
Mar 16, 2023
Merged
2 changes: 1 addition & 1 deletion .github/actions/deploy/appinfo/info.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<screenshot>https://raw.githubusercontent.com/nextcloud/cookbook/stable/img/screenshot2.png</screenshot>
<dependencies>
<php min-version="7.4"/>
<nextcloud min-version="25" max-version="26"/>
<nextcloud min-version="25" max-version="27"/>
</dependencies>
<navigations>
<navigation>
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [Unreleased]

### Changed
- Make info block visibility configurable
[1404](https://github.com/nextcloud/cookbook/pull/1404) @MarcelRobitaille

### Fixed
- Make "None" category string translatable
[#1323](https://github.com/nextcloud/cookbook/pull/1344) @seyfeb
Expand Down
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<screenshot>https://raw.githubusercontent.com/nextcloud/cookbook/stable/img/screenshot2.png</screenshot>
<dependencies>
<php min-version="7.4"/>
<nextcloud min-version="25" max-version="26"/>
<nextcloud min-version="25" max-version="27"/>
</dependencies>
<navigations>
<navigation>
Expand Down
7 changes: 7 additions & 0 deletions lib/Controller/Implementation/ConfigImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public function __construct(
$this->userFolder = $userFolder;
}

protected const KEY_VISIBLE_INFO_BLOCKS = 'visibleInfoBlocks';

/**
* Get the current configuration of the app
*
Expand All @@ -43,6 +45,7 @@ public function list() {
'folder' => $this->userFolder->getPath(),
'update_interval' => $this->dbCacheService->getSearchIndexUpdateInterval(),
'print_image' => $this->service->getPrintImage(),
self::KEY_VISIBLE_INFO_BLOCKS => $this->service->getVisibleInfoBlocks(),
], Http::STATUS_OK);
}

Expand Down Expand Up @@ -72,6 +75,10 @@ public function config() {
$this->service->setPrintImage((bool)$data['print_image']);
}

if (isset($data[self::KEY_VISIBLE_INFO_BLOCKS])) {
$this->service->setVisibleInfoBlocks($data[self::KEY_VISIBLE_INFO_BLOCKS]);
}

$this->dbCacheService->triggerCheck();

return new JSONResponse('OK', Http::STATUS_OK);
Expand Down
33 changes: 33 additions & 0 deletions lib/Helper/UserConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public function __construct(
protected const KEY_LAST_INDEX_UPDATE = 'last_index_update';
protected const KEY_UPDATE_INTERVAL = 'update_interval';
protected const KEY_PRINT_IMAGE = 'print_image';
protected const KEY_VISIBLE_INFO_BLOCKS = 'visible_info_blocks';
protected const KEY_FOLDER = 'folder';

/**
Expand Down Expand Up @@ -154,6 +155,38 @@ public function setPrintImage(bool $value): void {
}
}

/**
* Determines which info blocks are displayed next to the recipe
*
* @return array<string, bool> keys: info block ids, values: display state
* @throws UserNotLoggedInException if no user is logged in
*/
public function getVisibleInfoBlocks(): array {
$rawValue = $this->getRawValue(self::KEY_VISIBLE_INFO_BLOCKS);

if ($rawValue === '') {
return [
'preparation-time' => true,
'cooking-time' => true,
'total-time' => true,
'nutrition-information' => true,
'tools' => true,
];
}

return json_decode($rawValue, true);
}

/**
* Sets which info blocks are displayed next to the recipe
*
* @param array<string, bool> keys: info block ids, values: display state
* @throws UserNotLoggedInException if no user is logged in
*/
public function setVisibleInfoBlocks(array $visibleInfoBlocks): void {
$this->setRawValue(self::KEY_VISIBLE_INFO_BLOCKS, json_encode($visibleInfoBlocks));
}

/**
* Get the name of the default cookbook.
*
Expand Down
16 changes: 16 additions & 0 deletions lib/Service/RecipeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,22 @@ public function getPrintImage() {
return $this->userConfigHelper->getPrintImage();
}

/**
* Sets which info blocks are displayed next to the recipe
* @param array<string, bool> keys: info block ids, values: display state
*/
public function setVisibleInfoBlocks(array $visibleInfoBlocks) {
$this->userConfigHelper->setVisibleInfoBlocks($visibleInfoBlocks);
}

/**
* Determines which info blocks are displayed next to the recipe
* @return array<string, bool> keys: info block ids, values: display state
*/
public function getVisibleInfoBlocks(): array {
return $this->userConfigHelper->getVisibleInfoBlocks();
}

/**
* Get recipe file contents as an array
*
Expand Down
23 changes: 18 additions & 5 deletions src/components/RecipeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,27 @@
</div>
<div class="times">
<RecipeTimer
v-if="recipe.timerPrep"
v-if="
recipe.timerPrep &&
visibleInfoBlocks['preparation-time']
"
:value="recipe.timerPrep"
:timer="false"
:label="t('cookbook', 'Preparation time (H:MM)')"
/>
<RecipeTimer
v-if="recipe.timerCook"
v-if="
recipe.timerCook &&
visibleInfoBlocks['cooking-time']
"
:value="recipe.timerCook"
:timer="true"
:label="t('cookbook', 'Cooking time (H:MM)')"
/>
<RecipeTimer
v-if="recipe.timerTotal"
v-if="
recipe.timerTotal && visibleInfoBlocks['total-time']
"
:value="recipe.timerTotal"
:timer="false"
:label="t('cookbook', 'Total time (H:MM)')"
Expand All @@ -109,7 +117,7 @@
</ul>
</section>

<section class="tools">
<section v-if="visibleInfoBlocks.tools" class="tools">
<h3 v-if="parsedTools.length">
{{ t("cookbook", "Tools") }}
</h3>
Expand Down Expand Up @@ -446,9 +454,13 @@ export default {
return (
this.recipe.nutrition &&
!(this.recipe.nutrition instanceof Array) &&
Object.keys(this.recipe.nutrition).length > 1
Object.keys(this.recipe.nutrition).length > 1 &&
this.visibleInfoBlocks["nutrition-information"]
)
},
visibleInfoBlocks() {
return this.$store.state.config?.visibleInfoBlocks ?? {}
},
},
watch: {
recipe(r) {
Expand Down Expand Up @@ -861,6 +873,7 @@ main {
display: grid;

grid-template-columns: 1fr 1em 2fr;
grid-template-rows: 100% 100% 100% 1fr;

.ingredients {
grid-column: 1/2;
Expand Down
135 changes: 131 additions & 4 deletions src/components/SettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,84 @@
</ul>
</fieldset>
</NcAppSettingsSection>
<NcAppSettingsSection
id="settings-info-blocks"
:title="t('cookbook', 'Info blocks')"
class="app-settings-section"
>
<fieldset>
<legend class="settings-info-blocks__legend">
{{
t(
"cookbook",
"Control which blocks of information are shown in the recipe view. If you do not use some features and find them distracting, you may hide them."
)
}}
</legend>
<ul>
<li>
<input
id="info-blocks-checkbox-preparation-time"
v-model="visibleInfoBlocks"
type="checkbox"
class="checkbox"
value="preparation-time"
/>
<label for="info-blocks-checkbox-preparation-time">
{{ t("cookbook", "Preparation time") }}
</label>
</li>
<li>
<input
id="info-blocks-checkbox-cooking-time"
v-model="visibleInfoBlocks"
type="checkbox"
class="checkbox"
value="cooking-time"
/>
<label for="info-blocks-checkbox-cooking-time">
{{ t("cookbook", "Cooking time") }}
</label>
</li>
<li>
<input
id="info-blocks-checkbox-total-time"
v-model="visibleInfoBlocks"
type="checkbox"
class="checkbox"
value="total-time"
/>
<label for="info-blocks-checkbox-total-time">
{{ t("cookbook", "Total time") }}
</label>
</li>
<li>
<input
id="info-blocks-checkbox-nutrition-information"
v-model="visibleInfoBlocks"
type="checkbox"
class="checkbox"
value="nutrition-information"
/>
<label for="info-blocks-checkbox-nutrition-information">
{{ t("cookbook", "Nutrition information") }}
</label>
</li>
<li>
<input
id="info-blocks-checkbox-tools"
v-model="visibleInfoBlocks"
type="checkbox"
class="checkbox"
value="tools"
/>
<label for="info-blocks-checkbox-tools">
{{ t("cookbook", "Tools") }}
</label>
</li>
</ul>
</fieldset>
</NcAppSettingsSection>
</NcAppSettingsDialog>
</template>

Expand All @@ -98,6 +176,23 @@ import { showSimpleAlertModal } from "cookbook/js/modals"

export const SHOW_SETTINGS_EVENT = "show-settings"

const INFO_BLOCK_KEYS = [
"preparation-time",
"cooking-time",
"total-time",
"nutrition-information",
"tools",
]

// The Vue representation of multiple checkboxes is an array of all checked values
// However, the backend representation is an object (map of block ids to booleans)
const visibleInfoBlocksEncode = (arr) =>
Object.fromEntries(INFO_BLOCK_KEYS.map((key) => [key, arr.includes(key)]))
const visibleInfoBlocksDecode = (obj) =>
Object.entries(obj)
.filter(([, v]) => v)
.map(([k]) => k)

export default {
name: "SettingsDialog",
components: {
Expand All @@ -120,6 +215,8 @@ export default {
// (the one when config is loaded at page load)
resetInterval: true,
updateInterval: 0,
visibleInfoBlocks: [...INFO_BLOCK_KEYS],
resetVisibleInfoBlocks: true,
}
},
watch: {
Expand All @@ -130,7 +227,7 @@ export default {
return
}
try {
api.config.printImage.update(newVal)
await api.config.printImage.update(newVal)
// Should this check the response of the query? To catch some errors that redirect the page
} catch {
await showSimpleAlertModal(
Expand Down Expand Up @@ -169,6 +266,27 @@ export default {
this.updateInterval = oldVal
}
},
async visibleInfoBlocks(newVal, oldVal) {
// Avoid infinite loop on page load and when reseting value after failed submit
if (this.resetVisibleInfoBlocks) {
this.resetVisibleInfoBlocks = false
return
}
try {
const data = visibleInfoBlocksEncode(newVal)
await api.config.visibleInfoBlocks.update(data)
await this.$store.dispatch("refreshConfig")
// Should this check the response of the query? To catch some errors that redirect the page
} catch (err) {
// eslint-disable-next-line no-console
console.error("Error while trying to save info blocks", err)
await showSimpleAlertModal(
t("cookbook", "Could save visible info blocks")
)
this.resetVisibleInfoBlocks = true
this.visibleInfoBlocks = oldVal
}
},
},
mounted() {
this.setup()
Expand Down Expand Up @@ -218,20 +336,25 @@ export default {
*/
async setup() {
try {
const response = await api.config.get()
const config = response.data
await this.$store.dispatch("refreshConfig")
const { config } = this.$store.state
this.resetPrintImage = false
this.resetVisibleInfoBlocks = false

if (!config) {
throw new Error()
}

this.printImage = config.print_image
this.visibleInfoBlocks = visibleInfoBlocksDecode(
config.visibleInfoBlocks
)
this.showTagCloudInRecipeList =
this.$store.state.localSettings.showTagCloudInRecipeList
this.updateInterval = config.update_interval
this.recipeFolder = config.folder
} catch {
} catch (err) {
this.$log.error("Error setting up SettingsDialog", err)
await showSimpleAlertModal(
t("cookbook", "Loading config failed")
)
Expand Down Expand Up @@ -284,6 +407,10 @@ export default {
animation: rotate var(--animation-duration, 0.8s) linear infinite;
color: var(--color-loading-dark);
}

.settings-info-blocks__legend {
margin-bottom: 10px;
}
</style>

<style>
Expand Down
Loading