While still maintaining the ability to answer polls and send reactions in channels (when "read only" is false)
275 lines
No EOL
8.6 KiB
Vue
275 lines
No EOL
8.6 KiB
Vue
<template>
|
|
<div class="pa-4 create-root fill-height">
|
|
<YouAre v-if="loggedIn" class="mt-4" />
|
|
<div class="text-center">
|
|
<v-avatar class="create-image-small" size="50" color="#ededed" @click.stop="showAvatarPicker">
|
|
<v-img v-if="roomAvatar" :src="roomAvatar" />
|
|
<v-icon v-else>camera_alt</v-icon>
|
|
</v-avatar>
|
|
<div class="create-title">{{ $t("createchannel.title") }}</div>
|
|
<div class="create-info">{{ $t("createchannel.info") }}</div>
|
|
<div color="rgba(255,255,255,0.1)" class="text-center">
|
|
<v-form v-model="isValid" ref="form">
|
|
<v-text-field v-model="roomName" :label="$t('createchannel.channel_name')" color="black"
|
|
background-color="white" solo :rules="[(v) => !!v || $t('createchannel.name_required')]" required
|
|
v-on:keydown="message = null"></v-text-field>
|
|
<v-text-field v-model="roomTopic" :label="$t('createchannel.channel_topic')" color="black"
|
|
background-color="#F5F5F5" filled v-on:keydown="message = null"></v-text-field>
|
|
|
|
<!-- <div class="error--text" v-if="loadingLoginFlows">Loading login flows...</div> -->
|
|
|
|
<div class="error--text" v-if="message != null">{{ this.message }}</div>
|
|
|
|
<interactive-auth ref="interactiveAuth" />
|
|
|
|
<v-btn :disabled="!isValid || loading" color="primary" depressed block @click.stop="handleNext"
|
|
:loading="loading" class="filled-button mt-4">{{ $t("getlink.next") }}</v-btn>
|
|
<v-btn v-if="!loggedIn" color="black" depressed text block @click.stop="goToLoginPage" class="text-button">{{
|
|
$t("menu.login")
|
|
}}</v-btn>
|
|
</v-form>
|
|
</div>
|
|
</div>
|
|
|
|
<input id="room-avatar-picker" ref="avatar" type="file" name="avatar" @change="handlePickedAvatar($event)"
|
|
accept="image/*" class="d-none" />
|
|
|
|
<div :class="{ 'toast-at-bottom': true, 'visible': showQRCopiedToast }">{{ $t("getlink.qr_image_copied") }}</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import rememberMeMixin from "./rememberMeMixin";
|
|
import * as sdk from "matrix-js-sdk";
|
|
import logoMixin from "./logoMixin";
|
|
import InteractiveAuth from './InteractiveAuth.vue';
|
|
import util, { ROOM_TYPE_CHANNEL } from "../plugins/utils";
|
|
import YouAre from "../components/YouAre.vue";
|
|
import User from "../models/user";
|
|
import { CHANNEL_POWER_LEVELS } from "../services/matrix.service";
|
|
|
|
export default {
|
|
name: "CreateChannel",
|
|
mixins: [rememberMeMixin, logoMixin],
|
|
components: { InteractiveAuth, YouAre },
|
|
data() {
|
|
return this.defaultData();
|
|
},
|
|
computed: {
|
|
loggedIn() {
|
|
return this.$store.state.auth.status.loggedIn;
|
|
},
|
|
currentUser() {
|
|
return this.$store.state.auth.user;
|
|
},
|
|
},
|
|
watch: {
|
|
},
|
|
methods: {
|
|
defaultData() {
|
|
return {
|
|
roomName: "",
|
|
roomTopic: "",
|
|
isValid: false,
|
|
loading: false,
|
|
message: null,
|
|
currentLoginServer: "",
|
|
loadingLoginFlows: false,
|
|
loginFlows: null,
|
|
showQRCopiedToast: false,
|
|
roomAvatar: null,
|
|
roomAvatarFile: null,
|
|
};
|
|
},
|
|
goHome() {
|
|
this.$navigation.push({ name: "Home" }, -1);
|
|
},
|
|
goToLoginPage() {
|
|
this.$navigation.push({ name: "Login", params: { showCreateRoomOption: false, redirect: "GetLink" } }, 1);
|
|
},
|
|
handleNext() {
|
|
const prefix = this.$config.userIdPrefix;
|
|
const user = new User(util.randomUser(prefix), util.randomPass(), false);
|
|
|
|
// Reset errors
|
|
this.message = null;
|
|
this.loading = true;
|
|
|
|
const login = this.loggedIn ? Promise.resolve(this.currentUser) : this.loadLoginFlows().then(() => {
|
|
return this.$store.dispatch("createUser", { user, registrationFlowHandler: this.$refs.interactiveAuth.registrationFlowHandler })
|
|
});
|
|
login
|
|
.then(
|
|
(ignoreduser) => {
|
|
return this.createRoom();
|
|
})
|
|
.catch(
|
|
(ignorederror) => {
|
|
this.message = this.$t("createchannel.error_channel");
|
|
})
|
|
.finally(() => {
|
|
this.loading = false;
|
|
})
|
|
},
|
|
loadLoginFlows() {
|
|
var user = Object.assign({}, this.user);
|
|
return util.getMatrixBaseUrl(user, this.$config)
|
|
.then((baseUrl) => {
|
|
if (baseUrl !== this.currentLoginServer) {
|
|
this.currentLoginServer = baseUrl;
|
|
this.loadingLoginFlows = true;
|
|
|
|
const matrixClient = sdk.createClient({ baseUrl: baseUrl });
|
|
return matrixClient.loginFlows().then((response) => {
|
|
console.log("FLOWS", response.flows);
|
|
this.loginFlows = response.flows.filter(this.supportedLoginFlow);
|
|
this.loadingLoginFlows = false;
|
|
if (this.loginFlows.length == 0) {
|
|
this.message = this.$t('login.no_supported_flow')
|
|
} else {
|
|
this.message = null;
|
|
}
|
|
});
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
})
|
|
},
|
|
supportedLoginFlow(flow) {
|
|
return ["m.login.password"].includes(flow.type);
|
|
},
|
|
createRoom() {
|
|
const createRoomOptions = {
|
|
visibility: "private", // Not listed!
|
|
name: this.roomName,
|
|
preset: "public_chat",
|
|
initial_state:
|
|
[
|
|
{
|
|
type: "m.room.encryption",
|
|
state_key: "",
|
|
content: {
|
|
algorithm: "m.megolm.v1.aes-sha2",
|
|
},
|
|
},
|
|
{
|
|
type: "m.room.history_visibility",
|
|
state_key: "",
|
|
content: {
|
|
history_visibility: "joined"
|
|
}
|
|
},
|
|
{
|
|
type: "m.room.retention",
|
|
state_key: "",
|
|
content: {
|
|
max_lifetime: 3600 * 24 * 7 * 1000
|
|
}
|
|
}
|
|
]
|
|
};
|
|
if (this.roomTopic && this.roomTopic.length > 0) {
|
|
// Add topic
|
|
createRoomOptions.topic = this.roomTopic;
|
|
}
|
|
|
|
createRoomOptions.creation_content = {
|
|
type: ROOM_TYPE_CHANNEL
|
|
}
|
|
|
|
let roomId = "";
|
|
|
|
return util
|
|
.getUniqueAliasForRoomName(
|
|
this.$matrix.matrixClient,
|
|
this.roomName,
|
|
this.$matrix.currentUserMXDomain
|
|
)
|
|
.then((alias) => {
|
|
createRoomOptions.room_alias_name = alias;
|
|
})
|
|
.then(() => {
|
|
|
|
// Set power level event. Need to do that here, because we might not have the userId when the options object is created.
|
|
const powerLevels = {};
|
|
powerLevels[this.$matrix.currentUserId] = 100;
|
|
let powerLevelContent = {
|
|
users: powerLevels,
|
|
events_default: 50,
|
|
state_default: 50,
|
|
events: CHANNEL_POWER_LEVELS
|
|
}
|
|
createRoomOptions.initial_state.push(
|
|
{
|
|
type: "m.room.power_levels",
|
|
state_key: "",
|
|
content: powerLevelContent
|
|
});
|
|
|
|
return this.$matrix.matrixClient
|
|
.createRoom(createRoomOptions)
|
|
.then(({ room_id, room_alias }) => {
|
|
roomId = room_alias || room_id;
|
|
if (!this.roomAvatarFile) {
|
|
return true;
|
|
}
|
|
const self = this;
|
|
return util.setRoomAvatar(
|
|
this.$matrix.matrixClient,
|
|
room_id,
|
|
this.roomAvatarFile,
|
|
(p) => {
|
|
if (p.total) {
|
|
self.status = this.$t("new_room.status_avatar_total", {
|
|
count: p.loaded || 0,
|
|
total: p.total,
|
|
});
|
|
} else {
|
|
self.status = this.$t("new_room.status_avatar", {
|
|
count: p.loaded || 0,
|
|
});
|
|
}
|
|
}
|
|
);
|
|
});
|
|
})
|
|
.then(() => {
|
|
this.$navigation.push(
|
|
{
|
|
name: "Chat",
|
|
params: { roomId: util.sanitizeRoomId(roomId) },
|
|
},
|
|
-1
|
|
);
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Show picker to select room avatar file
|
|
*/
|
|
showAvatarPicker() {
|
|
this.$refs.avatar.click();
|
|
},
|
|
|
|
/**
|
|
* Handle picked avatar
|
|
*/
|
|
handlePickedAvatar(event) {
|
|
if (event.target.files && event.target.files[0]) {
|
|
var reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
this.roomAvatar = e.target.result;
|
|
this.roomAvatarFile = event.target.files[0];
|
|
};
|
|
reader.readAsDataURL(event.target.files[0]);
|
|
}
|
|
},
|
|
|
|
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "@/assets/css/create.scss";
|
|
</style> |