Merge pull request #23279 from nextcloud/enh/weather-favorites

Add favorite weather locations
This commit is contained in:
Roeland Jago Douma 2020-10-08 15:21:56 +02:00 committed by GitHub
commit 8b89172666
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 144 additions and 4 deletions

View File

@ -30,5 +30,7 @@ return [
['name' => 'WeatherStatus#getLocation', 'url' => '/api/v1/location', 'verb' => 'GET'], ['name' => 'WeatherStatus#getLocation', 'url' => '/api/v1/location', 'verb' => 'GET'],
['name' => 'WeatherStatus#setLocation', 'url' => '/api/v1/location', 'verb' => 'PUT'], ['name' => 'WeatherStatus#setLocation', 'url' => '/api/v1/location', 'verb' => 'PUT'],
['name' => 'WeatherStatus#getForecast', 'url' => '/api/v1/forecast', 'verb' => 'GET'], ['name' => 'WeatherStatus#getForecast', 'url' => '/api/v1/forecast', 'verb' => 'GET'],
['name' => 'WeatherStatus#getFavorites', 'url' => '/api/v1/favorites', 'verb' => 'GET'],
['name' => 'WeatherStatus#setFavorites', 'url' => '/api/v1/favorites', 'verb' => 'PUT'],
], ],
]; ];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -121,4 +121,27 @@ class WeatherStatusController extends OCSController {
return new DataResponse($forecast); return new DataResponse($forecast);
} }
} }
/**
* @NoAdminRequired
*
* Get favorites list
*
* @return DataResponse which contains the favorite list
*/
public function getFavorites(): DataResponse {
return new DataResponse($this->service->getFavorites());
}
/**
* @NoAdminRequired
*
* Set favorites list
*
* @param array $favorites
* @return DataResponse success state
*/
public function setFavorites(array $favorites): DataResponse {
return new DataResponse($this->service->setFavorites($favorites));
}
} }

View File

@ -133,6 +133,26 @@ class WeatherStatusService {
return ['success' => true]; return ['success' => true];
} }
/**
* Get favorites list
* @param array $favorites
* @return array success state
*/
public function getFavorites(): array {
$favoritesJson = $this->config->getUserValue($this->userId, Application::APP_ID, 'favorites', '');
return json_decode($favoritesJson, true) ?: [];
}
/**
* Set favorites list
* @param array $favorites
* @return array success state
*/
public function setFavorites(array $favorites): array {
$this->config->setUserValue($this->userId, Application::APP_ID, 'favorites', json_encode($favorites));
return ['success' => true];
}
/** /**
* Try to use the address set in user personal settings as weather location * Try to use the address set in user personal settings as weather location
* *

View File

@ -26,13 +26,18 @@
class="weather-status-menu-item__subheader" class="weather-status-menu-item__subheader"
:default-icon="weatherIcon" :default-icon="weatherIcon"
:menu-title="visibleMessage"> :menu-title="visibleMessage">
<ActionLink v-if="address && !errorMessage" <ActionLink v-if="gotWeather"
icon="icon-address" icon="icon-address"
target="_blank" target="_blank"
:href="weatherLinkTarget" :href="weatherLinkTarget"
:close-after-click="true"> :close-after-click="true">
{{ locationText }} {{ locationText }}
</ActionLink> </ActionLink>
<ActionButton v-if="gotWeather"
:icon="addRemoveFavoriteIcon"
@click="onAddRemoveFavoriteClick">
{{ addRemoveFavoriteText }}
</ActionButton>
<ActionSeparator v-if="address && !errorMessage" /> <ActionSeparator v-if="address && !errorMessage" />
<ActionButton <ActionButton
icon="icon-crosshair" icon="icon-crosshair"
@ -49,6 +54,18 @@
@submit="onAddressSubmit"> @submit="onAddressSubmit">
{{ t('weather_status', 'Set custom address') }} {{ t('weather_status', 'Set custom address') }}
</ActionInput> </ActionInput>
<ActionButton
v-show="favorites.length > 0"
:icon="toggleFavoritesIcon"
@click="showFavorites = !showFavorites">
{{ t('weather_status', 'Favorites') }}
</ActionButton>
<ActionButton v-for="f in displayedFavorites"
:key="f"
icon="icon-starred"
@click="onFavoriteClick(f)">
{{ f }}
</ActionButton>
</Actions> </Actions>
</div> </div>
</li> </li>
@ -160,6 +177,8 @@ export default {
lon: null, lon: null,
forecasts: [], forecasts: [],
loop: null, loop: null,
favorites: [],
showFavorites: false,
} }
}, },
computed: { computed: {
@ -217,6 +236,34 @@ export default {
weatherLinkTarget() { weatherLinkTarget() {
return 'https://www.windy.com/-Rain-thunder-rain?rain,' + this.lat + ',' + this.lon + ',11' return 'https://www.windy.com/-Rain-thunder-rain?rain,' + this.lat + ',' + this.lon + ',11'
}, },
gotWeather() {
return this.address && !this.errorMessage
},
addRemoveFavoriteIcon() {
return this.currentAddressIsFavorite
? 'icon-starred'
: 'icon-star'
},
addRemoveFavoriteText() {
return this.currentAddressIsFavorite
? t('weather_status', 'Remove from favorites')
: t('weather_status', 'Add as favorite')
},
currentAddressIsFavorite() {
return this.favorites.find((f) => {
return f === this.address
})
},
toggleFavoritesIcon() {
return this.showFavorites
? 'icon-triangle-s'
: 'icon-triangle-e'
},
displayedFavorites() {
return this.showFavorites
? this.favorites
: []
},
}, },
mounted() { mounted() {
this.initWeatherStatus() this.initWeatherStatus()
@ -235,6 +282,8 @@ export default {
} else if (this.mode === MODE_MANUAL_LOCATION) { } else if (this.mode === MODE_MANUAL_LOCATION) {
this.startLoop() this.startLoop()
} }
const favs = await network.getFavorites()
this.favorites = favs
} catch (err) { } catch (err) {
if (err?.code === 'ECONNABORTED') { if (err?.code === 'ECONNABORTED') {
console.info('The weather status request was cancelled because the user navigates.') console.info('The weather status request was cancelled because the user navigates.')
@ -378,6 +427,23 @@ export default {
? ((celcius * (9 / 5)) + 32).toFixed(1) ? ((celcius * (9 / 5)) + 32).toFixed(1)
: celcius : celcius
}, },
onAddRemoveFavoriteClick() {
const currentIsFavorite = this.currentAddressIsFavorite
if (currentIsFavorite) {
const i = this.favorites.indexOf(currentIsFavorite)
if (i !== -1) {
this.favorites.splice(i, 1)
}
} else {
this.favorites.push(this.address)
}
network.saveFavorites(this.favorites)
},
onFavoriteClick(favAddress) {
if (favAddress !== this.address) {
this.setAddress(favAddress)
}
},
}, },
} }
</script> </script>

View File

@ -106,6 +106,33 @@ const fetchForecast = async() => {
return response.data.ocs.data return response.data.ocs.data
} }
/**
* Fetches the location favorites
*
* @param {String} address The location
* @returns {Promise<Object>}
*/
const getFavorites = async() => {
const url = generateOcsUrl('apps/weather_status/api/v1', 2) + 'favorites'
const response = await HttpClient.get(url)
return response.data.ocs.data
}
/**
*
* @param {Array} favorites List of favorite addresses
* @returns {Promise<Object>}
*/
const saveFavorites = async(favorites) => {
const url = generateOcsUrl('apps/weather_status/api/v1', 2) + 'favorites'
const response = await HttpClient.put(url, {
favorites,
})
return response.data.ocs.data
}
export { export {
usePersonalAddress, usePersonalAddress,
setMode, setMode,
@ -113,4 +140,6 @@ export {
setLocation, setLocation,
setAddress, setAddress,
fetchForecast, fetchForecast,
getFavorites,
saveFavorites,
} }