summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2021-05-30 12:29:40 +0200
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2021-05-30 12:29:40 +0200
commitfec1798301f0dbe6986c775e4596b07ce27145d9 (patch)
tree7c4689cc35c7c9a35b363d6ec1d23d279cc82d51
parenta4a5ca65d06700b2524e9cde67151e2475bba6ca (diff)
Fix mobile details toggleenh/circles
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
-rw-r--r--src/components/AppContent/AppDetailsToggle.vue70
-rw-r--r--src/components/AppContent/CircleContent.vue15
-rw-r--r--src/components/EntityPicker/ContactsPicker.vue2
-rw-r--r--src/components/MemberList.vue60
-rw-r--r--src/models/member.d.ts2
-rw-r--r--src/models/member.ts9
-rw-r--r--src/views/Contacts.vue33
7 files changed, 137 insertions, 54 deletions
diff --git a/src/components/AppContent/AppDetailsToggle.vue b/src/components/AppContent/AppDetailsToggle.vue
new file mode 100644
index 00000000..f9c86b60
--- /dev/null
+++ b/src/components/AppContent/AppDetailsToggle.vue
@@ -0,0 +1,70 @@
+<!--
+ - @copyright Copyright (c) 2021 John Molakvoæ <skjnldsv@protonmail.com>
+ -
+ - @author John Molakvoæ <skjnldsv@protonmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+
+<template>
+ <a v-tooltip="t('contacts', 'Go back to the list')" class="app-details-toggle icon-confirm" href="#" />
+</template>
+
+<script>
+export default {
+ name: 'AppDetailsToggle',
+
+ beforeMount() {
+ this.toggleAppNavigationButton(true)
+ },
+
+ beforeDestroy() {
+ this.toggleAppNavigationButton(false)
+ },
+
+ methods: {
+ toggleAppNavigationButton(hide = true) {
+ const appNavigationToggle = document.querySelector('.app-navigation .app-navigation-toggle')
+ if (appNavigationToggle) {
+ appNavigationToggle.style.display = hide ? 'none' : null
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.app-details-toggle {
+ position: absolute;
+ width: 44px;
+ height: 44px;
+ padding: 14px;
+ cursor: pointer;
+ opacity: .6;
+ font-size: 16px;
+ line-height: 17px;
+ transform: rotate(180deg);
+ background-color: var(--color-main-background);
+ z-index: 2000;
+
+ &:active,
+ &:hover,
+ &:focus {
+ opacity: 1;
+ }
+}
+</style>
diff --git a/src/components/AppContent/CircleContent.vue b/src/components/AppContent/CircleContent.vue
index f49f76cf..d5e22f15 100644
--- a/src/components/AppContent/CircleContent.vue
+++ b/src/components/AppContent/CircleContent.vue
@@ -35,8 +35,10 @@
</div>
<div v-else id="app-content-wrapper">
+ <AppDetailsToggle v-if="isMobile && showDetails" @click.native.stop.prevent="hideDetails" />
+
<!-- member list -->
- <MemberList :list="members" :loading="loadingList" />
+ <MemberList :list="members" :loading="loadingList" :show-details.sync="showDetails" />
<!-- main contacts details -->
<CircleDetails :circle="circle">
@@ -73,9 +75,11 @@
<script>
import AppContent from '@nextcloud/vue/dist/Components/AppContent'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
+import isMobile from '@nextcloud/vue/dist/Mixins/isMobile'
import Login from 'vue-material-design-icons/Login'
+import AppDetailsToggle from '../AppContent/AppDetailsToggle'
import CircleDetails from '../CircleDetails'
import MemberList from '../MemberList'
import RouterMixin from '../../mixins/RouterMixin'
@@ -87,13 +91,14 @@ export default {
components: {
AppContent,
+ AppDetailsToggle,
CircleDetails,
EmptyContent,
Login,
MemberList,
},
- mixins: [RouterMixin],
+ mixins: [isMobile, RouterMixin],
props: {
loading: {
@@ -106,6 +111,7 @@ export default {
return {
loadingJoin: false,
loadingList: false,
+ showDetails: false,
}
},
@@ -168,6 +174,11 @@ export default {
}
},
+
+ // Hide the circle details
+ hideDetails() {
+ this.showDetails = false
+ },
},
}
</script>
diff --git a/src/components/EntityPicker/ContactsPicker.vue b/src/components/EntityPicker/ContactsPicker.vue
index 35b842f1..ef6f0f3f 100644
--- a/src/components/EntityPicker/ContactsPicker.vue
+++ b/src/components/EntityPicker/ContactsPicker.vue
@@ -9,7 +9,7 @@
<!-- contacts picker -->
<EntityPicker v-else-if="showPicker"
- :confirm-label="t('contacts', 'Add to {group}', { group: pickerforGroup.name})"
+ :confirm-label="t('contacts', 'Add to {group}', { group: pickerforGroup.name })"
:data-types="pickerTypes"
:data-set="pickerData"
@close="onContactPickerClose"
diff --git a/src/components/MemberList.vue b/src/components/MemberList.vue
index 5336f8bc..55652ec3 100644
--- a/src/components/MemberList.vue
+++ b/src/components/MemberList.vue
@@ -33,11 +33,16 @@
</EmptyContent>
</AppContentList>
- <AppContentList v-else :class="{ 'icon-loading': loading }">
+ <AppContentList v-else :class="{ 'icon-loading': loading, showdetails: showDetails }">
<div class="members-list__new">
<button class="icon-add" @click="onShowPicker(circle.id)">
{{ t('contacts', 'Add members') }}
</button>
+ <button v-if="isMobile"
+ class="icon-info"
+ @click="showCircleDetails">
+ {{ t('contacts', 'Show circle details') }}
+ </button>
</div>
<VirtualList class="members-list"
@@ -48,9 +53,9 @@
<!-- member picker -->
<EntityPicker v-if="showPicker"
- :confirm-label="t('contacts', 'Add to {circle}', { circle: circle.displayName})"
+ :confirm-label="t('contacts', 'Add to {circle}', { circle: circle.displayName })"
:data-types="pickerTypes"
- :data-set="pickerData"
+ :data-set="filteredPickerData"
:internal-search="false"
:loading="pickerLoading"
:selection.sync="pickerSelection"
@@ -63,6 +68,7 @@
<script>
import AppContentList from '@nextcloud/vue/dist/Components/AppContentList'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
+import isMobile from '@nextcloud/vue/dist/Mixins/isMobile'
import VirtualList from 'vue-virtual-scroll-list'
import MembersListItem from './MembersList/MembersListItem'
@@ -72,7 +78,7 @@ import RouterMixin from '../mixins/RouterMixin'
import { getRecommendations, getSuggestions } from '../services/collaborationAutocompletion'
import { showError, showWarning } from '@nextcloud/dialogs'
import { subscribe } from '@nextcloud/event-bus'
-import { SHARES_TYPES_MEMBER_MAP, CIRCLES_MEMBER_GROUPING, MemberTypes } from '../models/constants.ts'
+import { SHARES_TYPES_MEMBER_MAP, CIRCLES_MEMBER_GROUPING } from '../models/constants.ts'
export default {
name: 'MemberList',
@@ -83,7 +89,7 @@ export default {
EntityPicker,
EmptyContent,
},
- mixins: [RouterMixin],
+ mixins: [isMobile, RouterMixin],
props: {
list: {
@@ -95,11 +101,17 @@ export default {
type: Boolean,
default: false,
},
+
+ showDetails: {
+ type: Boolean,
+ default: false,
+ },
},
data() {
return {
MembersListItem,
+
pickerLoading: false,
showPicker: false,
showPickerIntro: true,
@@ -121,20 +133,18 @@ export default {
return this.$store.getters.getCircle(this.selectedCircle)
},
- filteredList() {
+ groupedList() {
// Group per userType
- const groupedList = this.list.reduce(function(r, a) {
- // If the user type is a circle, this could originate from multiple sources
- const userType = a.userType !== MemberTypes.CIRCLE
- ? a.userType
- : a.basedOn.source
-
- r[userType] = r[userType] || []
- r[userType].push(a)
- return r
+ return this.list.reduce(function(list, member) {
+ const userType = member.userType
+ list[userType] = list[userType] || []
+ list[userType].push(member)
+ return list
}, Object.create(null))
+ },
- return Object.keys(groupedList)
+ filteredList() {
+ return Object.keys(this.groupedList)
// Object.keys returns string
.map(type => parseInt(type, 10))
// Map populated types to the group entry
@@ -143,7 +153,7 @@ export default {
.map(group => [{
heading: true,
...group,
- }, ...(groupedList[group.type] || [])])
+ }, ...(this.groupedList[group.type] || [])])
// Merging sub-arrays
.flat()
},
@@ -151,6 +161,18 @@ export default {
hasMembers() {
return this.filteredList.length > 0
},
+
+ filteredPickerData() {
+ return this.pickerData.filter(entity => {
+ const type = SHARES_TYPES_MEMBER_MAP[entity.shareType]
+ const list = this.groupedList[type]
+ if (list) {
+ return list.find(member => member.userId === entity.shareWith) === undefined
+ }
+ // If the type doesn't exists, there is no member of this type
+ return true
+ })
+ },
},
mounted() {
@@ -249,6 +271,10 @@ export default {
this.pickerData = []
this.pickerSelection = {}
},
+
+ showCircleDetails() {
+ this.$emit('update:showDetails', true)
+ },
},
}
</script>
diff --git a/src/models/member.d.ts b/src/models/member.d.ts
index b779c194..ea3a75e9 100644
--- a/src/models/member.d.ts
+++ b/src/models/member.d.ts
@@ -59,7 +59,7 @@ export default class Member {
/**
* Member based on source
*/
- get basedOn(): Object;
+ get basedOn(): any;
/**
* Member level
*
diff --git a/src/models/member.ts b/src/models/member.ts
index b62e6aad..4707a65a 100644
--- a/src/models/member.ts
+++ b/src/models/member.ts
@@ -21,7 +21,7 @@
*/
import Circle from './circle'
-import { MemberLevel, MemberLevels, MemberType } from './constants'
+import { MemberLevel, MemberLevels, MemberType, MemberTypes } from './constants'
export default class Member {
@@ -95,13 +95,16 @@ export default class Member {
* Member type
*/
get userType(): MemberType {
- return this._data.userType
+ // If the user type is a circle, this could originate from multiple sources
+ return this._data.userType !== MemberTypes.CIRCLE
+ ? this._data.userType
+ : this.basedOn.source
}
/**
* Member based on source
*/
- get basedOn(): Object {
+ get basedOn(): any {
return this._data.basedOn
}
diff --git a/src/views/Contacts.vue b/src/views/Contacts.vue
index c336115f..a616377b 100644
--- a/src/views/Contacts.vue
+++ b/src/views/Contacts.vue
@@ -24,10 +24,7 @@
<template>
<Content app-name="contacts">
<!-- go back to list when in details mode -->
- <a v-if="selectedContact && isMobile"
- class="app-details-toggle icon-confirm"
- href="#"
- @click.stop.prevent="showList" />
+ <AppDetailsToggle v-if="isMobile && selectedContact" @click.native.stop.prevent="showList" />
<!-- new-contact-button + navigation + settings -->
<RootNavigation
@@ -76,6 +73,7 @@ import Modal from '@nextcloud/vue/dist/Components/Modal'
import { showError } from '@nextcloud/dialogs'
import { VCardTime } from 'ical.js'
+import AppDetailsToggle from '../components/AppContent/AppDetailsToggle'
import CircleContent from '../components/AppContent/CircleContent'
import ContactsContent from '../components/AppContent/ContactsContent'
import ContactsPicker from '../components/EntityPicker/ContactsPicker'
@@ -91,6 +89,7 @@ export default {
name: 'Contacts',
components: {
+ AppDetailsToggle,
AppNavigationNew,
CircleContent,
ContactsContent,
@@ -399,29 +398,3 @@ export default {
},
}
</script>
-
-<style lang="scss" scoped>
-.app-details-toggle {
- position: absolute;
- width: 44px;
- height: 44px;
- padding: 14px;
- cursor: pointer;
- opacity: .6;
- font-size: 16px;
- line-height: 17px;
- transform: rotate(180deg);
- background-color: var(--color-main-background);
- z-index: 2000;
- &:active,
- &:hover,
- &am