diff --git a/src/router/mobile.ts b/src/router/mobile.ts
index e10290a1..4a823502 100644
--- a/src/router/mobile.ts
+++ b/src/router/mobile.ts
@@ -44,6 +44,7 @@ import CategoryEditPage from '@/views/mobile/categories/EditPage.vue';
import CategoryPresetPage from '@/views/mobile/categories/PresetPage.vue';
import TagListPage from '@/views/mobile/tags/ListPage.vue';
+import TagGroupListPage from '@/views/mobile/tags/GroupListPage.vue';
import TemplateListPage from '@/views/mobile/templates/ListPage.vue';
@@ -324,6 +325,11 @@ const routes: Router.RouteParameters[] = [
async: asyncResolve(TagListPage),
beforeEnter: [checkLogin]
},
+ {
+ path: '/tag/group/list',
+ async: asyncResolve(TagGroupListPage),
+ beforeEnter: [checkLogin]
+ },
{
path: '/template/list',
async: asyncResolve(TemplateListPage),
diff --git a/src/views/mobile/tags/GroupListPage.vue b/src/views/mobile/tags/GroupListPage.vue
new file mode 100644
index 00000000..77bd5aab
--- /dev/null
+++ b/src/views/mobile/tags/GroupListPage.vue
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/mobile/tags/ListPage.vue b/src/views/mobile/tags/ListPage.vue
index 22e5ef22..cd97f6d9 100644
--- a/src/views/mobile/tags/ListPage.vue
+++ b/src/views/mobile/tags/ListPage.vue
@@ -12,7 +12,7 @@
-
+
@@ -178,6 +178,17 @@
+
+ {{ tt('Add Tag Group') }}
+ {{ tt('Rename Tag Group') }}
+ {{ tt('Delete Tag Group') }}
+
+
+ {{ tt('Change Group Display Order') }}
+
{{ tt('Sort') }}
{{ tt('Show Hidden Transaction Tags') }}
@@ -211,7 +222,9 @@ import { useTagListPageBase } from '@/views/base/tags/TagListPageBase.ts';
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { TextDirection } from '@/core/text.ts';
+import { DEFAULT_TAG_GROUP_ID } from '@/consts/tag.ts';
+import { TransactionTagGroup } from '@/models/transaction_tag_group.ts';
import { TransactionTag } from '@/models/transaction_tag.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
@@ -222,7 +235,7 @@ const props = defineProps<{
}>();
const { tt, getCurrentLanguageTextDirection } = useI18n();
-const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
+const { showAlert, showConfirm, showPrompt, showToast, routeBackOnError } = useI18nUIComponents();
const {
activeTagGroupId,
@@ -510,6 +523,94 @@ function cancelSort(): void {
});
}
+function addTagGroup(): void {
+ showPrompt(tt('New Tag Group Name'), '', (value: string) => {
+ showLoading();
+
+ transactionTagsStore.saveTagGroup({
+ tagGroup: TransactionTagGroup.createNewTagGroup(value)
+ }).then(tagGroup => {
+ hideLoading();
+ activeTagGroupId.value = tagGroup.id;
+ }).catch(error => {
+ hideLoading();
+
+ if (!error.processed) {
+ showToast(error.message || error);
+ }
+ });
+ });
+}
+
+function renameTagGroup(): void {
+ const tagGroup = transactionTagsStore.allTransactionTagGroupsMap[activeTagGroupId.value];
+
+ if (!tagGroup) {
+ showToast('Unable to rename this tag group');
+ return;
+ }
+
+ showPrompt(tt('Rename Tag Group'), tagGroup.name || '', (value: string) => {
+ showLoading();
+
+ const newTagGroup = tagGroup.clone();
+ newTagGroup.name = value;
+
+ transactionTagsStore.saveTagGroup({
+ tagGroup: newTagGroup
+ }).then(() => {
+ hideLoading();
+ }).catch(error => {
+ hideLoading();
+
+ if (!error.processed) {
+ showToast(error.message || error);
+ }
+ });
+ });
+}
+
+function removeTagGroup(): void {
+ const tagGroup = transactionTagsStore.allTransactionTagGroupsMap[activeTagGroupId.value];
+
+ if (!tagGroup) {
+ showToast('Unable to delete this tag group');
+ return;
+ }
+
+ const currentTagGroupIndex = allTagGroupsWithDefault.value.findIndex(group => group.id === tagGroup.id);
+
+ showConfirm('Are you sure you want to delete this tag group?', () => {
+ showLoading();
+
+ transactionTagsStore.deleteTagGroup({
+ tagGroup: tagGroup
+ }).then(() => {
+ hideLoading();
+
+ if (allTagGroupsWithDefault.value[currentTagGroupIndex]) {
+ const newActiveTagGroup = allTagGroupsWithDefault.value[currentTagGroupIndex];
+ activeTagGroupId.value = newActiveTagGroup ? newActiveTagGroup.id : DEFAULT_TAG_GROUP_ID;
+ } else if (allTagGroupsWithDefault.value[currentTagGroupIndex - 1]) {
+ const newActiveTagGroup = allTagGroupsWithDefault.value[currentTagGroupIndex - 1];
+ activeTagGroupId.value = newActiveTagGroup ? newActiveTagGroup.id : DEFAULT_TAG_GROUP_ID;
+ } else {
+ activeTagGroupId.value = DEFAULT_TAG_GROUP_ID;
+ }
+ }).catch(error => {
+ hideLoading();
+
+ if (!error.processed) {
+ showToast(error.message || error);
+ }
+ });
+ });
+}
+
+function changeTagGroupDisplayOrder(): void {
+ props.f7router.navigate('/tag/group/list');
+}
+
function onSort(event: { el: { id: string }, from: number, to: number }): void {
if (!event || !event.el || !event.el.id) {
showToast('Unable to move tag');