+
+
+
+
+
+
+ {{ tt('No transaction data') }}
+
+
+
+
+
+ {{ getDisplayLongDate(transactions[0] as Transaction) }}
+
+ {{ getWeekdayLongName((transactions[0] as Transaction).displayDayOfWeek as WeekDay) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ tt('Failed to load image, please check whether the config "domain" and "root_url" are set correctly.') }}
+
+
+
+
+
+
+
+
+
+
+
+
@@ -681,6 +727,7 @@ import {
type Year0BasedMonth,
type LocalizedRecentMonthDateRange,
type TimeRangeAndDateType,
+ type WeekDay,
DateRangeScene,
DateRange
} from '@/core/datetime.ts';
@@ -720,6 +767,7 @@ import {
categoryTypeToTransactionType,
transactionTypeToCategoryType
} from '@/lib/category.ts';
+import { allTransactionPictures } from '@/lib/transaction.ts';
import { isDataExportingEnabled, isDataImportingEnabled, isTransactionFromAIImageRecognitionEnabled } from '@/lib/server_settings.ts';
import { scrollToSelectedItem, startDownloadFile } from '@/lib/ui/common.ts';
import logger from '@/lib/logger.ts';
@@ -739,7 +787,8 @@ import {
mdiArrowRight,
mdiPound,
mdiMagicStaff,
- mdiTextBoxOutline
+ mdiTextBoxOutline,
+ mdiTextBoxEditOutline
} from '@mdi/js';
interface TransactionListProps {
@@ -830,6 +879,7 @@ const {
getDisplayAmount,
getDisplayMonthTotalAmount,
getTransactionTypeName,
+ getTransactionPictureUrl
} = useTransactionListPageBase();
const settingsStore = useSettingsStore();
@@ -886,7 +936,7 @@ const allPageCounts = computed
(() => {
return pageCounts;
});
-const recentMonthDateRanges = computed(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type, true));
+const recentMonthDateRanges = computed(() => getAllRecentMonthDateRanges(pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type, true));
const allTransactionTemplates = computed(() => {
const allTemplates = transactionTemplatesStore.allVisibleTemplates;
@@ -902,7 +952,7 @@ const allowCategoryTypes = computed(() => {
});
const transactions = computed(() => {
- if (pageType.value === TransactionListPageType.List.type) {
+ if (pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type) {
if (queryMonthlyData.value) {
const transactionData = currentMonthTransactionData.value;
@@ -942,6 +992,22 @@ const transactions = computed(() => {
}
});
+const transactionsByDay = computed>(() => {
+ const transactionsByDay: Record = {};
+
+ for (const transaction of transactions.value) {
+ if (!transaction.gregorianCalendarYearDashMonthDashDay) {
+ continue;
+ }
+
+ const transactions: Transaction[] = transactionsByDay[transaction.gregorianCalendarYearDashMonthDashDay] ?? [];
+ transactions.push(transaction);
+ transactionsByDay[transaction.gregorianCalendarYearDashMonthDashDay] = transactions;
+ }
+
+ return transactionsByDay;
+});
+
const recentDateRangeIndex = computed({
get: () => getRecentDateRangeIndex(recentMonthDateRanges.value, query.value.dateType, query.value.minTime, query.value.maxTime, firstDayOfWeek.value, fiscalYearStart.value),
set: (value) => {
@@ -1166,6 +1232,7 @@ function init(initProps: TransactionListProps): void {
function reload(force: boolean, init: boolean): void {
loading.value = true;
+ const isGalleryMode = pageType.value === TransactionListPageType.Gallery.type;
const page = currentPage.value;
Promise.all([
@@ -1188,6 +1255,8 @@ function reload(force: boolean, init: boolean): void {
return transactionsStore.loadMonthlyAllTransactions({
year: currentYear,
month: currentMonth,
+ mustHavePictures: isGalleryMode,
+ withPictures: isGalleryMode,
autoExpand: true,
defaultCurrency: defaultCurrency.value
});
@@ -1196,7 +1265,9 @@ function reload(force: boolean, init: boolean): void {
reload: true,
count: countPerPage.value,
page: page,
+ mustHavePictures: isGalleryMode,
withCount: page <= 1,
+ withPictures: isGalleryMode,
autoExpand: true,
defaultCurrency: defaultCurrency.value
});
@@ -1896,4 +1967,8 @@ init(props);
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span.transaction-calendar-daily-amount {
font-size: 0.95rem;
}
+
+.transaction-gallery-container {
+ color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
+}
diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue
index eb88f3af..c9f74fd5 100644
--- a/src/views/mobile/transactions/ListPage.vue
+++ b/src/views/mobile/transactions/ListPage.vue
@@ -80,10 +80,10 @@
-
-
+
-
+
@@ -147,6 +148,21 @@
+
+
+
+
+
+
+
@@ -156,14 +172,14 @@
-
-
+
+
+
+
+
+
+
+
+ {{ tt('Failed to load image, please check whether the config "domain" and "root_url" are set correctly.') }}
+
+
+
+
+
+
+
+ v-if="pageType === TransactionListPageType.List.type || pageType === TransactionListPageType.Gallery.type">
{{ tt('Load More') }}
@@ -309,7 +346,7 @@
:class="{ 'list-item-selected': query.dateType === dateRange.type }"
:key="dateRange.type"
v-for="dateRange in allDateRanges"
- v-show="pageType === TransactionListPageType.List.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type"
+ v-show="pageType === TransactionListPageType.List.type || pageType === TransactionListPageType.Gallery.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type"
@click="changeDateFilter(dateRange.type)">
@@ -661,6 +698,7 @@ import {
categoryTypeToTransactionType,
transactionTypeToCategoryType
} from '@/lib/category.ts';
+import { allTransactionPictures } from '@/lib/transaction.ts';
const props = defineProps<{
f7route: Router.Route;
@@ -727,6 +765,7 @@ const {
getDisplayAmount,
getDisplayMonthTotalAmount,
getTransactionTypeName,
+ getTransactionPictureUrl
} = useTransactionListPageBase();
const environmentsStore = useEnvironmentsStore();
@@ -753,7 +792,7 @@ const transactions = computed(() => {
return [];
}
- if (pageType.value === TransactionListPageType.List.type) {
+ if (pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type) {
return transactionsStore.transactions;
} else if (pageType.value === TransactionListPageType.Calendar.type) {
if (queryMonthlyData.value) {
@@ -796,7 +835,7 @@ const transactions = computed(() => {
});
const noTransaction = computed(() => {
- if (pageType.value === TransactionListPageType.List.type) {
+ if (pageType.value === TransactionListPageType.List.type || pageType.value === TransactionListPageType.Gallery.type) {
return transactionsStore.noTransaction;
} else if (pageType.value === TransactionListPageType.Calendar.type) {
return !transactions.value || !transactions.value.length || !transactions.value[0]!.items || !transactions.value[0]!.items.length;
@@ -962,6 +1001,8 @@ function reload(done?: () => void): void {
loading.value = true;
}
+ const isGalleryMode = pageType.value === TransactionListPageType.Gallery.type;
+
transactionInvisibleYearMonths.value = {};
transactionYearMonthListHeights.value = {};
@@ -978,12 +1019,16 @@ function reload(done?: () => void): void {
return transactionsStore.loadMonthlyAllTransactions({
year: currentYear,
month: currentMonth,
+ mustHavePictures: isGalleryMode,
+ withPictures: isGalleryMode,
autoExpand: true,
defaultCurrency: defaultCurrency.value
});
} else {
return transactionsStore.loadTransactions({
reload: true,
+ mustHavePictures: isGalleryMode,
+ withPictures: isGalleryMode,
autoExpand: true,
defaultCurrency: defaultCurrency.value
});
@@ -1023,10 +1068,14 @@ function loadMore(autoExpand: boolean): void {
return;
}
+ const isGalleryMode = pageType.value === TransactionListPageType.Gallery.type;
+
loadingMore.value = true;
transactionsStore.loadTransactions({
reload: false,
+ mustHavePictures: isGalleryMode,
+ withPictures: isGalleryMode,
autoExpand: autoExpand,
defaultCurrency: defaultCurrency.value
}).then(() => {
@@ -1060,6 +1109,8 @@ function changePageType(type: number): void {
reload();
}
}
+ } else {
+ reload();
}
}
@@ -1702,4 +1753,83 @@ html[dir="rtl"] .list.transaction-info-list li.transaction-info .transaction-foo
.transaction-calendar-container .dp__main .dp__calendar .dp__calendar_row > .dp__calendar_item .transaction-calendar-daily-amounts > span.transaction-calendar-daily-amount {
font-size: var(--ebk-transaction-calendar-amount-font-size);
}
+
+.transaction-gallery-list.list > ul {
+ overflow: hidden;
+}
+
+.transaction-gallery-list.list > ul::before,
+.transaction-gallery-list.list > ul::after {
+ display: none;
+}
+
+.transaction-gallery-container > .item-content {
+ padding: 0;
+}
+
+.transaction-gallery-container > .item-content > .item-inner {
+ padding: 0;
+ min-height: 0;
+}
+
+.transaction-gallery-container > .item-content > .item-inner::after {
+ display: none;
+}
+
+.transaction-gallery-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 2px;
+ width: 100%;
+}
+
+@media (min-width: 480px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
+
+@media (min-width: 640px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(5, 1fr);
+ }
+}
+
+@media (min-width: 800px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(6, 1fr);
+ }
+}
+
+@media (min-width: 960px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(7, 1fr);
+ }
+}
+
+@media (min-width: 1024px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(8, 1fr);
+ }
+}
+
+@media (min-width: 1280px) {
+ .transaction-gallery-grid {
+ grid-template-columns: repeat(9, 1fr);
+ }
+}
+
+.transaction-picture-cell {
+ position: relative;
+ display: block;
+ aspect-ratio: 1;
+ overflow: hidden;
+ background-color: var(--f7-list-bg-color);
+}
+
+.transaction-picture-img {
+ width: 100%;
+ height: 100%;
+ display: block;
+}