autocomplete for weather location search #23

pull/1/head
Thomas Ballmann 4 years ago
parent d45c978b61
commit 54ed1b27fd

@ -0,0 +1,107 @@
<template>
<v-autocomplete
:disabled="!api"
v-model="model"
:items="entries"
:loading="isLoading"
:search-input.sync="search"
hide-no-data
hide-selected
item-text="name"
item-value="id"
label="i8n:Location"
placeholder="i8n:Start typing to Search"
_return-object
>
<template v-slot:item="{ item }">
<v-list-item two-line class="pa-0">
<v-list-item-icon class="ma-0">
<img width="64" :src="getConditionIcon(item.weather[0].icon)" />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ item.name }}, {{ item.sys.country }}
<img :src="getCountryFlag(item.sys.country)" />
<strong>{{ item.weather[0].description }}</strong>
</v-list-item-title>
<v-list-item-subtitle>
<v-chip class="font-weight-bold" small>{{ item.main.temp }}°С</v-chip>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item></v-list-item>
</template>
</v-autocomplete>
</template>
<script>
export default {
props: {
location: {
type: Number,
required: true
},
api: {
type: String,
required: true
},
lang: {
type: String,
required: true
},
unit: {
type: String,
required: true
}
},
data: () => ({
entries: [],
isLoading: false,
model: null,
search: null
}),
watch: {
model(val) {
this.$emit("update:location", val);
},
search(val) {
if (!val || val.length < 3) return;
// Items have already been requested
if (this.isLoading) return;
this.isLoading = true;
// search
let url = "https://api.openweathermap.org/data/2.5/find?appid=";
url += this.api;
url += "&lang=" + this.lang;
url += "&units=" + this.unit;
url += "&type=like&sort=population&cnt=10";
url += "&q=" + val;
fetch(url)
.then(res => res.json())
.then(res => {
this.count = res.count;
this.entries = res.list;
})
.catch(err => {
console.log(err);
})
.finally(() => (this.isLoading = false));
}
},
methods: {
getCountryFlag(code) {
return (
"http://openweathermap.org/images/flags/" + code.toLowerCase() + ".png"
);
},
getConditionIcon(code) {
return "http://openweathermap.org/img/wn/" + code + "@2x.png";
}
}
};
</script>

@ -1,219 +1,255 @@
<template> <template>
<v-layout fluid fill-height> <v-layout fluid fill-height>
<template v-if="isLoading"> <template v-if="isLoading">
<v-overlay :absolute="true" :value="true"> <v-overlay :absolute="true" :value="true">
<v-progress-circular indeterminate size="64"></v-progress-circular> <v-progress-circular indeterminate size="64"></v-progress-circular>
</v-overlay> </v-overlay>
</template> </template>
<v-container> <v-container>
<v-snackbar <v-snackbar v-model="isSnackbar" :timeout="3000" color="success">i8n:saved</v-snackbar>
v-model="isSnackbar"
:timeout="3000" <v-tabs v-model="tab" centered icons-and-text>
color="success" <v-tab>
> Device
i8n:saved <v-icon>$tv</v-icon>
</v-snackbar> </v-tab>
<v-tab>
<v-tabs v-model="tab" centered icons-and-text> Playlist
<v-tab>Device <v-icon>$tv</v-icon></v-tab> <v-icon>$playlist</v-icon>
<v-tab>Playlist <v-icon>$playlist</v-icon></v-tab> </v-tab>
<v-tab>Weather <v-icon>$wb_sunny</v-icon></v-tab> <v-tab>
<v-tab>Cloud <v-icon>$cloud</v-icon></v-tab> Weather
</v-tabs> <v-icon>$wb_sunny</v-icon>
</v-tab>
<v-card <v-tab>
v-if="settings" Cloud
class="mx-auto" <v-icon>$cloud</v-icon>
width="400" </v-tab>
> </v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item> <v-card v-if="settings" class="mx-auto" width="400">
<v-card-text> <v-tabs-items v-model="tab">
<v-select <v-tab-item>
:items="deviceOrientation" <v-card-text>
v-model="settings.device.angle" <v-select
label="i8n:Orientation" :items="deviceOrientation"
placeholder="" v-model="settings.device.angle"
></v-select> label="i8n:Orientation"
placeholder
<v-select ></v-select>
:items="deviceTheme"
v-model="settings.device.theme" <v-select
label="i8n:Theme" :items="deviceTheme"
placeholder="" v-model="settings.device.theme"
></v-select> label="i8n:Theme"
</v-card-text> placeholder
</v-tab-item> ></v-select>
<v-tab-item> </v-card-text>
<v-card-text class="pb-0"> </v-tab-item>
<v-row> <v-tab-item>
<v-col cols="3" class="text-center mt-2 pb-0"> <v-card-text class="pb-0">
<v-icon>$wb_sunny</v-icon><br/> <v-row>
Forecast <v-col cols="3" class="text-center mt-2 pb-0">
</v-col> <v-icon>$wb_sunny</v-icon>
<v-col cols="6" class="text-center pb-0"> <br />Forecast
<v-text-field </v-col>
v-model="settings.playlist.timer" <v-col cols="6" class="text-center pb-0">
label="Switch every" <v-text-field
type="number" v-model="settings.playlist.timer"
dense label="Switch every"
rounded type="number"
filled dense
suffix="seconds" rounded
class="text-right" filled
></v-text-field> suffix="seconds"
</v-col> class="text-right"
<v-col cols="3" class="text-center mt-2 pb-0"> ></v-text-field>
<v-icon>$calendar_today</v-icon><br/> </v-col>
Calendar <v-col cols="3" class="text-center mt-2 pb-0">
</v-col> <v-icon>$calendar_today</v-icon>
</v-row> <br />Calendar
</v-col>
<ul class="mt-5" v-if="0"> </v-row>
<li>calendar</li>
<li>weather forecast</li> <ul class="mt-5" v-if="0">
<li>unsplash.com</li> <li>calendar</li>
</ul> <li>weather forecast</li>
</v-card-text> <li>unsplash.com</li>
</v-tab-item> </ul>
<v-tab-item> </v-card-text>
<v-card-text> </v-tab-item>
<v-text-field <v-tab-item>
label="i8n:OpenWeatherMap" <v-card-text>
v-model="settings.weather.api" <v-text-field
placeholder="###" label="i8n:OpenWeatherMap"
></v-text-field> v-model="settings.weather.api"
<v-text-field placeholder="###"
label="i8n:Location" ></v-text-field>
v-model="settings.weather.location"
placeholder="" <weather-find-location
></v-text-field> :api="settings.weather.api"
<v-select :location.sync="settings.weather.location"
:items="weatherLang" :lang="settings.weather.lang"
v-model="settings.weather.lang" :unit="settings.weather.unit"
label="i8n:Lang" ></weather-find-location>
placeholder=""
></v-select> <v-select
<v-select :items="weatherLang"
:items="weatherUnit" v-model="settings.weather.lang"
v-model="settings.weather.unit" label="i8n:Lang"
label="i8n:Units" placeholder
placeholder="" ></v-select>
></v-select> <v-select
</v-card-text> :items="weatherUnit"
</v-tab-item> v-model="settings.weather.unit"
<v-tab-item> label="i8n:Units"
<v-card-text> placeholder
<v-select ></v-select>
:items="deviceMode" </v-card-text>
v-model="settings.cloud.mode" </v-tab-item>
label="i8n:Device mode" <v-tab-item>
placeholder="" <v-card-text>
></v-select> <v-select
:items="deviceMode"
<v-text-field v-model="settings.cloud.mode"
label="i8n:Cloud server" label="i8n:Device mode"
v-model="settings.cloud.url" placeholder
placeholder="i8n:https://" ></v-select>
></v-text-field>
<v-text-field
<v-text-field label="i8n:Cloud server"
label="i8n:Cloud Token" v-model="settings.cloud.url"
v-model="settings.cloud.token" placeholder="i8n:https://"
placeholder="########-####-####-####-############" ></v-text-field>
></v-text-field>
</v-card-text> <v-text-field
</v-tab-item> label="i8n:Cloud Token"
</v-tabs-items> v-model="settings.cloud.token"
placeholder="########-####-####-####-############"
<v-card-actions> ></v-text-field>
<v-spacer></v-spacer> </v-card-text>
</v-tab-item>
<v-btn </v-tabs-items>
text
color="primary" <v-card-actions>
@click="onSave()" <v-spacer></v-spacer>
>
i8n:Save <v-btn text color="primary" @click="onSave()">i8n:Save</v-btn>
</v-btn> </v-card-actions>
</v-card-actions> </v-card>
</v-card> </v-container>
</v-container> </v-layout>
</v-layout>
</template> </template>
<script> <script>
import apiDevice from '../api/device' import apiDevice from "../api/device";
import weatherFindLocation from "./../components/WeatherFindLocation";
export default {
name: "Settings", export default {
data: () => ({ name: "Settings",
isLoading: true, components: {
isSnackbar: false, weatherFindLocation
tab: 0, },
data: () => ({
settings: null, isLoading: true,
isSnackbar: false,
// 0 thru 3 corresponding to 4 cardinal rotations tab: 0,
deviceOrientation: [
{text: 'Nord', value: 0}, settings: null,
{text: 'East', value: 1},
{text: 'South', value: 2}, // 0 thru 3 corresponding to 4 cardinal rotations
{text: 'West', value: 3}, deviceOrientation: [
], { text: "Nord", value: 0 },
deviceTheme: [ { text: "East", value: 1 },
{text: 'Black', value: 'black'}, { text: "South", value: 2 },
{text: 'White', value: 'white'}, { text: "West", value: 3 }
], ],
deviceMode: [ deviceTheme: [
{text: 'Active', value: 'active'}, { text: "Black", value: "black" },
{text: 'Passive', value: 'passive'} { text: "White", value: "white" }
], ],
deviceMode: [
// @see https://openweathermap.org/current#multi { text: "Active", value: "active" },
weatherLang: [ { text: "Passive", value: "passive" }
{text: 'Deutsch', value: 'de'}, ],
{text: 'English', value: 'en'}
], // @see https://openweathermap.org/current#multi
weatherUnit: [ weatherLang: [
{text: 'Metrisch', value: 'metric'}, { text: "English", value: "en" },
{text: 'Imperial', value: ''} { text: "Deutsch", value: "de" }
], ],
weatherUnit: [
}), { text: "Imperial", value: "" },
created () { { text: "Metrisch", value: "metric" }
this.$vuetify.icons.values.tv = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/tv/baseline.svg')} ]
this.$vuetify.icons.values.playlist = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/live_tv/baseline.svg')} // slideshow | playlist_play | live_tv | queue_play_next }),
this.$vuetify.icons.values.keys = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/insert_link/baseline.svg')} created() {
this.$vuetify.icons.values.cloud = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/cloud/baseline.svg')} this.$vuetify.icons.values.tv = {
this.$vuetify.icons.values.calendar_today = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/calendar_today/baseline.svg')} component: () =>
this.$vuetify.icons.values.wb_sunny = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg')} import(
this.$vuetify.icons.values.update = {component: () => import(/* webpackChunkName: "icons" */'!vue-svg-loader!@material-icons/svg/svg/update/baseline.svg')} /* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/tv/baseline.svg"
)
apiDevice.getSettings(settings => { };
this.settings = settings this.$vuetify.icons.values.playlist = {
component: () =>
this.isLoading = false import(
}) /* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/live_tv/baseline.svg"
}, )
methods: { }; // slideshow | playlist_play | live_tv | queue_play_next
onSave () { this.$vuetify.icons.values.keys = {
this.isLoading = true component: () =>
import(
apiDevice.putSettings(this.settings, (data) => { /* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/insert_link/baseline.svg"
console.log(data) )
this.isLoading = false };
this.isSnackbar = true this.$vuetify.icons.values.cloud = {
}) component: () =>
import(
} /* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/cloud/baseline.svg"
} )
};
this.$vuetify.icons.values.calendar_today = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/calendar_today/baseline.svg"
)
};
this.$vuetify.icons.values.wb_sunny = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/wb_sunny/baseline.svg"
)
};
this.$vuetify.icons.values.update = {
component: () =>
import(
/* webpackChunkName: "icons" */ "!vue-svg-loader!@material-icons/svg/svg/update/baseline.svg"
)
};
apiDevice.getSettings(settings => {
this.settings = settings;
this.isLoading = false;
});
},
methods: {
onSave() {
this.isLoading = true;
apiDevice.putSettings(this.settings, data => {
console.log(data);
this.isLoading = false;
this.isSnackbar = true;
});
} }
}
};
</script> </script>
<style scoped> <style scoped>
>>>.v-input.text-right .v-text-field__slot > input { >>> .v-input.text-right .v-text-field__slot > input {
text-align: right; text-align: right;
} }
</style> </style>

Loading…
Cancel
Save