work on player
This commit is contained in:
		@ -39,11 +39,10 @@ export default {
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        get(index) { return this.set.get(index) },
 | 
			
		||||
        find(item) { return this.set.find(item) },
 | 
			
		||||
        findIndex(item) { return this.set.findIndex(item) },
 | 
			
		||||
        find(pred) { return this.set.find(pred) },
 | 
			
		||||
        findIndex(pred) { return this.set.findIndex(pred) },
 | 
			
		||||
 | 
			
		||||
        push(...items) {
 | 
			
		||||
            let index = this.set.length;
 | 
			
		||||
            for(var item of items)
 | 
			
		||||
                this.set.push(item);
 | 
			
		||||
        },
 | 
			
		||||
@ -62,7 +61,10 @@ export default {
 | 
			
		||||
            return this.selectedIndex;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        unselect() {
 | 
			
		||||
            this.$emit('unselect', { item: this.selected, index: this.selectedIndex});
 | 
			
		||||
            this.selectedIndex = -1;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -119,7 +119,6 @@ export class Set {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get length() { return this.items.length }
 | 
			
		||||
    get(index) { return this.items[index] }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch multiple items from server
 | 
			
		||||
@ -156,17 +155,24 @@ export class Set {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Find item by id
 | 
			
		||||
     * Get item at index
 | 
			
		||||
     */
 | 
			
		||||
    find(item) {
 | 
			
		||||
        return this.items.find(x => x.id == item.id);
 | 
			
		||||
    get(index) { return this.items[index] }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Find an item by id or using a predicate function
 | 
			
		||||
     */
 | 
			
		||||
    find(pred) {
 | 
			
		||||
        return pred instanceof Function ? this.items.find(pred)
 | 
			
		||||
                                        : this.items.find(x => x.id == pred.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Find item index by id
 | 
			
		||||
     * Find item index by id or using a predicate function
 | 
			
		||||
     */
 | 
			
		||||
    findIndex(item) {
 | 
			
		||||
        return this.items.findIndex(x => x.id == item.id);
 | 
			
		||||
    findIndex(pred) {
 | 
			
		||||
        return pred instanceof Function ? this.items.findIndex(pred)
 | 
			
		||||
                                        : this.items.findIndex(x => x.id == pred.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -177,7 +183,7 @@ export class Set {
 | 
			
		||||
        if(this.unique) {
 | 
			
		||||
            let index = this.findIndex(item);
 | 
			
		||||
            if(index > -1)
 | 
			
		||||
                this.items.splice(index,1);
 | 
			
		||||
                return;
 | 
			
		||||
        }
 | 
			
		||||
        if(this.max && this.items.length >= this.max)
 | 
			
		||||
            this.items.splice(0,this.items.length-this.max)
 | 
			
		||||
 | 
			
		||||
@ -1,37 +1,28 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="player">
 | 
			
		||||
        <Playlist ref="history" class="player-panel menu" v-show="panel == 'history'"
 | 
			
		||||
            name="History"
 | 
			
		||||
            :editable="true" :player="self" :set="sets.history" @select="play('pin', $event.index)"
 | 
			
		||||
            listClass="menu-list" itemClass="menu-item">
 | 
			
		||||
            <template v-slot:header="">
 | 
			
		||||
                <p class="menu-label">
 | 
			
		||||
                    <span class="icon"><span class="fa fa-clock"></span></span>
 | 
			
		||||
                    History
 | 
			
		||||
                </p>
 | 
			
		||||
            </template>
 | 
			
		||||
        </Playlist>
 | 
			
		||||
        <Playlist ref="pin" class="player-panel menu" v-show="panel == 'pin'"
 | 
			
		||||
            name="Pinned"
 | 
			
		||||
            :editable="true" :player="self" :set="sets.pin" @select="play('pin', $event.index)" 
 | 
			
		||||
            listClass="menu-list" itemClass="menu-item">
 | 
			
		||||
            <template v-slot:header="">
 | 
			
		||||
                <p class="menu-label">
 | 
			
		||||
                    <span class="icon"><span class="fa fa-thumbtack"></span></span>
 | 
			
		||||
                    Pinned
 | 
			
		||||
                </p>
 | 
			
		||||
            </template>
 | 
			
		||||
        </Playlist>
 | 
			
		||||
        <Playlist ref="queue" class="player-panel menu" v-show="panel == 'queue'"
 | 
			
		||||
            :editable="true" :player="self" :set="sets.queue" @select="play('queue', $event.index)" 
 | 
			
		||||
            listClass="menu-list" itemClass="menu-item">
 | 
			
		||||
            <template v-slot:header="">
 | 
			
		||||
                <p class="menu-label">
 | 
			
		||||
                    <span class="icon"><span class="fa fa-list"></span></span>
 | 
			
		||||
                    Playlist
 | 
			
		||||
                </p>
 | 
			
		||||
            </template>
 | 
			
		||||
        </Playlist>
 | 
			
		||||
        <div :class="['player-panels', panel ? 'is-open' : '']">
 | 
			
		||||
            <Playlist ref="pin" class="player-panel menu" v-show="panel == 'pin'"
 | 
			
		||||
                name="Pinned"
 | 
			
		||||
                :editable="true" :player="self" :set="sets.pin" @select="play('pin', $event.index)" 
 | 
			
		||||
                listClass="menu-list" itemClass="menu-item">
 | 
			
		||||
                <template v-slot:header="">
 | 
			
		||||
                    <p class="menu-label">
 | 
			
		||||
                        <span class="icon"><span class="fa fa-thumbtack"></span></span>
 | 
			
		||||
                        Pinned
 | 
			
		||||
                    </p>
 | 
			
		||||
                </template>
 | 
			
		||||
            </Playlist>
 | 
			
		||||
            <Playlist ref="queue" class="player-panel menu" v-show="panel == 'queue'"
 | 
			
		||||
                :editable="true" :player="self" :set="sets.queue" @select="play('queue', $event.index)" 
 | 
			
		||||
                listClass="menu-list" itemClass="menu-item">
 | 
			
		||||
                <template v-slot:header="">
 | 
			
		||||
                    <p class="menu-label">
 | 
			
		||||
                        <span class="icon"><span class="fa fa-list"></span></span>
 | 
			
		||||
                        Playlist
 | 
			
		||||
                    </p>
 | 
			
		||||
                </template>
 | 
			
		||||
            </Playlist>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="player-bar media">
 | 
			
		||||
            <div class="media-left">
 | 
			
		||||
@ -47,24 +38,18 @@
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="media-content">
 | 
			
		||||
                <slot name="content" :current="current"></slot>
 | 
			
		||||
                <Progress v-if="this.duration" :value="this.currentTime" :max="this.duration"
 | 
			
		||||
                <Progress v-if="loaded && duration" :value="currentTime" :max="this.duration"
 | 
			
		||||
                    :format="displayTime"
 | 
			
		||||
                    @select="audio.currentTime = $event"></Progress>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="media-right">
 | 
			
		||||
                <button class="button has-text-weight-bold" v-if="loaded" @click="playLive()">
 | 
			
		||||
                    <span class="icon has-text-danger">
 | 
			
		||||
                        <span class="fa fa-broadcast-tower"></span>
 | 
			
		||||
                    <span class="icon is-size-6 has-text-danger">
 | 
			
		||||
                        <span class="fa fa-circle"></span>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span>Live</span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <button :class="playlistButtonClass('history')"
 | 
			
		||||
                        @click="togglePanel('history')">
 | 
			
		||||
                    <span class="mr-2 is-size-6" v-if="sets.history.length">
 | 
			
		||||
                        {{ sets.history.length }}</span>
 | 
			
		||||
                    <span class="icon"><span class="fa fa-clock"></span></span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <button :class="playlistButtonClass('pin')"
 | 
			
		||||
                <button ref="pinPlaylistButton" :class="playlistButtonClass('pin')"
 | 
			
		||||
                        @click="togglePanel('pin')">
 | 
			
		||||
                    <span class="mr-2 is-size-6" v-if="sets.pin.length">
 | 
			
		||||
                        {{ sets.pin.length }}</span>
 | 
			
		||||
@ -86,7 +71,7 @@
 | 
			
		||||
import Vue, { ref } from 'vue';
 | 
			
		||||
import Live from './live';
 | 
			
		||||
import Playlist from './playlist';
 | 
			
		||||
import Progress from './playerProgress';
 | 
			
		||||
import Progress from './progress';
 | 
			
		||||
import Sound from './sound';
 | 
			
		||||
import {Set} from './model';
 | 
			
		||||
 | 
			
		||||
@ -111,7 +96,7 @@ export default {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            audio, duration: 0, currentTime: 0,
 | 
			
		||||
            audio, duration: 0, currentTime: 0, state: State.paused,
 | 
			
		||||
 | 
			
		||||
            /// Live instance
 | 
			
		||||
            live: this.liveArgs ? new Live(this.liveArgs) : null,
 | 
			
		||||
@ -125,7 +110,6 @@ export default {
 | 
			
		||||
            sets: {
 | 
			
		||||
                queue: Set.storeLoad(Sound, "playlist.queue", { max: 30, unique: true }),
 | 
			
		||||
                pin: Set.storeLoad(Sound, "player.pin", { max: 30, unique: true }),
 | 
			
		||||
                history: Set.storeLoad(Sound, "player.history", { max: 30, unique: true }),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@ -159,7 +143,11 @@ export default {
 | 
			
		||||
            seconds = (seconds - s) / 60;
 | 
			
		||||
            let m = seconds % 60;
 | 
			
		||||
            let h = (seconds - m) / 60;
 | 
			
		||||
            return h ? `${h}:${m}:${s}` : `${m}:${s}`;
 | 
			
		||||
 | 
			
		||||
            let [ss,mm,hh] = [s.toString().padStart(2, '0'),
 | 
			
		||||
                              m.toString().padStart(2, '0'),
 | 
			
		||||
                              h.toString().padStart(2, '0')];
 | 
			
		||||
            return h ? `${hh}:${mm}:${ss}` : `${mm}:${ss}`;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        playlistButtonClass(name) {
 | 
			
		||||
@ -172,24 +160,23 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        /// Show/hide panel
 | 
			
		||||
        togglePanel(panel) {
 | 
			
		||||
            this.panel = this.panel == panel ? null : panel;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        togglePanel(panel) { this.panel = this.panel == panel ? null : panel },
 | 
			
		||||
        /// Return True if item is loaded
 | 
			
		||||
        isLoaded(item) {
 | 
			
		||||
            return this.loaded && this.loaded.src == item.src;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        isLoaded(item) { return this.loaded && this.loaded.id == item.id },
 | 
			
		||||
        /// Return True if item is loaded
 | 
			
		||||
        isPlaying(item) {
 | 
			
		||||
            return this.isLoaded(item) && !this.player.paused;
 | 
			
		||||
        isPlaying(item) { return this.isLoaded(item) && !this.paused },
 | 
			
		||||
 | 
			
		||||
        _setPlaylist(playlist) {
 | 
			
		||||
            this.playlist = playlist ? this.$refs[playlist] : null;
 | 
			
		||||
            for(var p in this.sets)
 | 
			
		||||
                if(p != playlist)
 | 
			
		||||
                    this.$refs[p].unselect();
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        load(playlist, {src=null, item=null}={}) {
 | 
			
		||||
            src = src || item.src;
 | 
			
		||||
            this.loaded = item;
 | 
			
		||||
            this.playlist = playlist ? this.$refs[playlist] : null;
 | 
			
		||||
            this._setPlaylist(playlist);
 | 
			
		||||
 | 
			
		||||
            const audio = this.audio;
 | 
			
		||||
            if(src instanceof Array) {
 | 
			
		||||
@ -217,8 +204,7 @@ export default {
 | 
			
		||||
            console.log('play', playlist, index, this.audio);
 | 
			
		||||
            let item = this.$refs[playlist].get(index);
 | 
			
		||||
            if(item) {
 | 
			
		||||
                this.load(playlist, {item: item});
 | 
			
		||||
                this.sets.history.push(item);
 | 
			
		||||
                this.load(playlist, {item});
 | 
			
		||||
                this.audio.play().catch(e => console.error(e))
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@ -266,8 +252,7 @@ export default {
 | 
			
		||||
                this.sets.pin.remove(index);
 | 
			
		||||
            else {
 | 
			
		||||
                this.sets.pin.push(item);
 | 
			
		||||
                if(!this.panel)
 | 
			
		||||
                    this.panel = 'pin';
 | 
			
		||||
                this.$refs.pinPlaylistButton.focus();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,46 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="media">
 | 
			
		||||
        <div class="media-left">
 | 
			
		||||
            <slot name="value" :value="value" :max="max">{{ format(value) }}</slot>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div ref="bar" class="media-content" @click.stop="onClick">
 | 
			
		||||
            <div :class="progressClass" :style="progressStyle"> </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="media-right">
 | 
			
		||||
            <slot name="value" :value="value" :max="max">{{ format(max) }}</slot>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        value: Number,
 | 
			
		||||
        max: Number,
 | 
			
		||||
        format: { type: Function, default: x => x },
 | 
			
		||||
        progressClass: { default: 'has-background-primary' },
 | 
			
		||||
        vertical: { type: Boolean, default: false },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
        progressStyle() {
 | 
			
		||||
            if(!this.max)
 | 
			
		||||
                return null;
 | 
			
		||||
            return this.vertical ? { height: (this.max ? this.value * 100 / this.max : 0) + '%' }
 | 
			
		||||
                                 : { width: (this.max ? this.value * 100 / this.max : 0) + '%' };
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        xToValue(x) { return x * this.max / this.$refs.bar.getBoundingClientRect().width },
 | 
			
		||||
        yToValue(y) { return y * this.max / this.$refs.bar.getBoundingClientRect().height },
 | 
			
		||||
 | 
			
		||||
        onClick(event) {
 | 
			
		||||
            let rect = event.currentTarget.getBoundingClientRect()
 | 
			
		||||
            this.$emit('select', this.vertical ? this.yToValue(event.clientY - rect.y)
 | 
			
		||||
                                               : this.xToValue(event.clientX - rect.x));
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										67
									
								
								assets/public/progress.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								assets/public/progress.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="media">
 | 
			
		||||
        <div class="media-left">
 | 
			
		||||
            <slot name="value" :value="valueDisplay" :max="max">{{ format(valueDisplay) }}</slot>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div ref="bar" class="media-content" @click.stop="onClick" @mouseleave.stop="onMouseMove"
 | 
			
		||||
                @mousemove.stop="onMouseMove">
 | 
			
		||||
            <div :class="progressClass" :style="progressStyle"> </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="media-right">
 | 
			
		||||
            <slot name="value" :value="valueDisplay" :max="max">{{ format(max) }}</slot>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            hoverValue: null,
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    props: {
 | 
			
		||||
        value: Number,
 | 
			
		||||
        max: Number,
 | 
			
		||||
        format: { type: Function, default: x => x },
 | 
			
		||||
        progressClass: { default: 'has-background-primary' },
 | 
			
		||||
        vertical: { type: Boolean, default: false },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
        valueDisplay() { return this.hoverValue === null ? this.value : this.hoverValue; },
 | 
			
		||||
 | 
			
		||||
        progressStyle() {
 | 
			
		||||
            if(!this.max)
 | 
			
		||||
                return null;
 | 
			
		||||
            let value = this.max ? this.valueDisplay * 100 / this.max : 0;
 | 
			
		||||
            return this.vertical ? { height: `${value}%` } : { width: `${value}%` };
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        xToValue(x) { return x * this.max / this.$refs.bar.getBoundingClientRect().width },
 | 
			
		||||
        yToValue(y) { return y * this.max / this.$refs.bar.getBoundingClientRect().height },
 | 
			
		||||
 | 
			
		||||
        valueFromEvent(event) {
 | 
			
		||||
            let rect = event.currentTarget.getBoundingClientRect()
 | 
			
		||||
            return this.vertical ? this.yToValue(event.clientY - rect.y)
 | 
			
		||||
                                 : this.xToValue(event.clientX - rect.x);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        onClick(event) {
 | 
			
		||||
            this.$emit('select', this.valueFromEvent(event));
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        onMouseMove(event) {
 | 
			
		||||
            if(event.type == 'mouseleave')
 | 
			
		||||
                this.hoverValue = null;
 | 
			
		||||
            else {
 | 
			
		||||
                this.hoverValue = this.valueFromEvent(event);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
        <div class="media-left" v-if="hasAction('play')">
 | 
			
		||||
            <button class="button" @click="$emit('togglePlay')">
 | 
			
		||||
                <div class="icon">
 | 
			
		||||
                    <span class="fa fa-pause" v-if="playing || loading"></span>
 | 
			
		||||
                    <span class="fa fa-pause" v-if="playing"></span>
 | 
			
		||||
                    <span class="fa fa-play" v-else></span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </button>
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
            </slot>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="media-right">
 | 
			
		||||
            <button class="button" v-if="player.$refs.pin != $parent" @click.stop="player.togglePin(item)">
 | 
			
		||||
            <button class="button" v-if="player.sets.pin != $parent.set" @click.stop="player.togglePin(item)">
 | 
			
		||||
                <span class="icon is-small">
 | 
			
		||||
                    <span :class="(pinned ? '' : 'has-text-grey-light ') + 'fa fa-thumbtack'"></span>
 | 
			
		||||
                </span>
 | 
			
		||||
@ -43,9 +43,8 @@ export default {
 | 
			
		||||
    computed: {
 | 
			
		||||
        item() { return this.data instanceof Model ? this.data : new Sound(this.data || {}); },
 | 
			
		||||
        loaded() { return this.player && this.player.isLoaded(this.item) },
 | 
			
		||||
        playing() { return this.player && this.player.playing && this.loaded },
 | 
			
		||||
        playing() { return this.player && this.player.isPlaying(this.item) },
 | 
			
		||||
        paused()  { return this.player && this.player.paused && this.loaded },
 | 
			
		||||
        loading() { return this.player && this.player.loading && this.loaded },
 | 
			
		||||
        pinned() { return this.player && this.player.sets.pin.find(this.item) },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -172,12 +172,27 @@ a.navbar-item.is-active {
 | 
			
		||||
.player {
 | 
			
		||||
    box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6);
 | 
			
		||||
 | 
			
		||||
    .player-panels {
 | 
			
		||||
        height: 0%;
 | 
			
		||||
        transition: height 3s;
 | 
			
		||||
    }
 | 
			
		||||
    .player-panels.is-open {
 | 
			
		||||
        height: auto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .player-panel {
 | 
			
		||||
        margin: 0.4em;
 | 
			
		||||
        max-height: 80%;
 | 
			
		||||
        overflow-y: auto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .progress {
 | 
			
		||||
        margin: 0em;
 | 
			
		||||
        padding: 0em;
 | 
			
		||||
        border-color: $info;
 | 
			
		||||
        border-style: 'solid';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .player-bar {
 | 
			
		||||
        border-top: 1px $grey-light solid;
 | 
			
		||||
 | 
			
		||||
@ -204,6 +219,11 @@ a.navbar-item.is-active {
 | 
			
		||||
            height: 2.5em;
 | 
			
		||||
            min-width: 2.5em;
 | 
			
		||||
            border-radius: 0px;
 | 
			
		||||
            transition: background-color 1s;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .button:focus {
 | 
			
		||||
            background-color: $info;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user