Skip to content

Commit 492d602

Browse files
committed
Merge remote-tracking branch 'origin/master' into onmax/tour
2 parents 3f22464 + 0fd0d6b commit 492d602

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1217
-962
lines changed

public/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
<head>
55
<meta charset="utf-8">
66
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7-
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0">
7+
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,viewport-fit=cover">
8+
<meta name="theme-color" content="white" media="(prefers-color-scheme: light)">
9+
<meta name="theme-color" content="#1f2348" media="(prefers-color-scheme: dark)">
810
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
911
<title>Nimiq Wallet</title>
1012
<link href="https://fonts.googleapis.com/css?family=Muli:400,600,700" rel="stylesheet">

src/App.vue

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<Tour/>
66
</transition>
77

8-
<main :class="routeClass" ref="$main">
8+
<main :class="activeMobileColumn" ref="$main">
99
<Sidebar/>
1010

1111
<transition name="delay">
@@ -32,50 +32,22 @@
3232
<script lang="ts">
3333
import { defineComponent, ref, watch, computed, onMounted, Ref } from '@vue/composition-api';
3434
import { LoadingSpinner } from '@nimiq/vue-components';
35-
3635
import Sidebar from './components/layouts/Sidebar.vue';
3736
import SwapNotification from './components/swap/SwapNotification.vue';
3837
import UpdateNotification from './components/UpdateNotification.vue';
39-
import router, { provideRouter, Columns } from './router';
38+
import router, { provideRouter } from './router';
4039
import { useAccountStore } from './stores/Account';
4140
import { useSettingsStore } from './stores/Settings';
4241
import { useWindowSize } from './composables/useWindowSize';
42+
import { useActiveMobileColumn } from './composables/useActiveMobileColumn';
4343
import { useSwipes } from './composables/useSwipes';
4444
4545
export default defineComponent({
4646
name: 'app',
4747
setup(props, context) {
4848
provideRouter(router);
4949
50-
const routeClass = ref('');
51-
52-
watch(() => context.root.$route.meta, (meta) => {
53-
if (!meta) return;
54-
// Using a watcher, because the routeClass should only change when a route is visited
55-
// that may require a column navigation. When opening modals, we don't want to change
56-
// column.
57-
switch (meta.column) {
58-
case Columns.DYNAMIC:
59-
switch (context.root.$route.path) {
60-
case '/': routeClass.value = 'column-account'; break;
61-
case '/transactions': routeClass.value = 'column-address'; break;
62-
default: break; // Don't change column
63-
}
64-
break;
65-
case Columns.ACCOUNT: routeClass.value = 'column-account'; break;
66-
case Columns.ADDRESS: routeClass.value = 'column-address'; break;
67-
default: break;
68-
}
69-
});
70-
71-
watch(() => context.root.$route.query, (newQuery, oldQuery) => {
72-
if (!newQuery) return;
73-
if (newQuery.sidebar) {
74-
routeClass.value = 'column-sidebar';
75-
} else if (oldQuery && oldQuery.sidebar) {
76-
routeClass.value = 'column-account';
77-
}
78-
});
50+
const { activeMobileColumn } = useActiveMobileColumn();
7951
8052
const { accountInfos, state: accountState, setTour } = useAccountStore();
8153
if (!['root', 'transactions'].includes(context.root.$route.name as string)
@@ -92,7 +64,7 @@ export default defineComponent({
9264
// Swiping
9365
const $main = ref<HTMLDivElement>(null);
9466
let $mobileTapArea: HTMLDivElement | null = null;
95-
const { width } = useWindowSize();
67+
const { width, isMobile } = useWindowSize();
9668
9769
async function updateSwipeRestPosition(
9870
velocityDistance: number,
@@ -161,23 +133,23 @@ export default defineComponent({
161133
excludeSelector: '.scroller, .scroller *',
162134
});
163135
164-
watch([width, swipingEnabled], ([newWidth, newSwiping], [oldWidth, oldSwiping]) => {
136+
watch([isMobile, swipingEnabled], ([isMobileNow, newSwiping], [wasMobile, oldSwiping]) => {
165137
if (!$main.value) return;
166138
167-
if ((newWidth <= 700 && oldWidth > 700) || (newSwiping === 1 && oldSwiping !== 1)) {
139+
if ((isMobileNow && !wasMobile) || (newSwiping === 1 && oldSwiping !== 1)) {
168140
attachSwipe();
169-
} else if (newWidth > 700 || newSwiping !== 1) {
141+
} else if (!isMobileNow || newSwiping !== 1) {
170142
detachSwipe();
171143
}
172144
}, { lazy: true });
173145
174146
onMounted(() => {
175-
if (width.value <= 700 && swipingEnabled.value === 1) attachSwipe();
147+
if (isMobile.value && swipingEnabled.value === 1) attachSwipe();
176148
});
177149
178150
return {
179151
showTour,
180-
routeClass,
152+
activeMobileColumn,
181153
hasAccounts,
182154
amountsHidden,
183155
$main,
@@ -373,6 +345,10 @@ body {
373345
display: block;
374346
}
375347
348+
.nq-card {
349+
padding-bottom: env(safe-area-inset-bottom);
350+
}
351+
376352
.fade-enter-active, .fade-leave-active {
377353
transition: opacity var(--transition-time) cubic-bezier(0.5, 0, 0.15, 1);
378354

src/components/AccountBalance.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ export default defineComponent({
6363
const $fiatAmountContainer = ref<HTMLDivElement>(null);
6464
const $fiatAmount = ref<Vue>(null);
6565
66-
const { width: windowWidth } = useWindowSize();
67-
const fiatAmountMaxSize = computed(() => windowWidth.value > 1160 ? 7 : 5.5); // rem
66+
const { isFullDesktop } = useWindowSize();
67+
const fiatAmountMaxSize = computed(() => isFullDesktop.value ? 7 : 5.5); // rem
6868
const fiatAmountFontSize = ref(fiatAmountMaxSize.value);
6969
7070
async function updateFontSize() {

src/components/AddressList.vue

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@
77
:class="{ 'active': activeAddress === addressInfo.address && activeCurrency === CryptoCurrency.NIM }"
88
@click="selectAddress(addressInfo.address);"
99
:ref="`address-button-${addressInfo.address}`"/>
10-
<hr class="separator" v-if="showBitcoin"/>
11-
<AddressListItem
12-
v-if="showBitcoin"
13-
:addressInfo="btcInfos"
14-
:class="{ 'active': activeCurrency === CryptoCurrency.BTC }"
15-
@click="selectBtcAddress()"
16-
:ref="`address-button-${btcInfos.address}`"/>
1710
<button
1811
v-if="showAddAddressButton"
1912
class="address-button add-address-button reset flex-row"
@@ -24,12 +17,19 @@
2417
</div>
2518
<span class="label add-address-label">{{ $t('Add\u00a0address') }}</span>
2619
</button>
20+
<div class="scroll-mask bottom"></div>
21+
<hr class="separator" v-if="showBitcoin"/>
22+
<AddressListItem
23+
v-if="showBitcoin"
24+
:addressInfo="btcInfos"
25+
:class="{ 'active': activeCurrency === CryptoCurrency.BTC }"
26+
@click="selectBtcAddress()"
27+
:ref="`address-button-${btcInfos.address}`"/>
2728
<div v-if="!embedded"
2829
class="active-box"
2930
:class="{ enabled: activeCurrency === CryptoCurrency.NIM }"
3031
:style="`--backgroundYScale: ${backgroundYScale}; --backgroundYOffset: ${backgroundYOffset}px`"
3132
></div>
32-
<div class="scroll-mask bottom"></div>
3333
</div>
3434
</template>
3535

@@ -212,6 +212,7 @@ export default defineComponent({
212212
}
213213
214214
.address-list {
215+
height: 100%;
215216
display: flex;
216217
flex-direction: column;
217218
position: relative;
@@ -230,6 +231,7 @@ export default defineComponent({
230231
231232
hr.separator {
232233
margin: 15px 0 15px 0;
234+
margin-top: auto;
233235
border-top: 1.5px solid var(--nimiq-blue);
234236
opacity: 0.14;
235237
}
@@ -379,5 +381,9 @@ export default defineComponent({
379381
.add-address-button {
380382
padding: 1.5rem;
381383
}
384+
385+
.embedded ::v-deep .mobile-arrow {
386+
display: inherit;
387+
}
382388
}
383389
</style>

src/components/BalanceDistribution.vue

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,12 @@ import { useSwapsStore } from '../stores/Swaps';
116116
export default defineComponent({
117117
name: 'balance-distribution',
118118
setup() {
119-
const { activeAccountInfo } = useAccountStore();
119+
const { hasBitcoinAddresses } = useAccountStore();
120120
const { addressInfos, accountBalance } = useAddressStore();
121121
const { accountBalance: btcAccountBalance } = useBtcAddressStore();
122122
const { currency: fiatCurrency, exchangeRates } = useFiatStore();
123123
const { btcUnit, canUseSwaps } = useSettingsStore();
124124
125-
const hasBitcoinAddresses = computed(() => (activeAccountInfo.value || false)
126-
&& (activeAccountInfo.value.btcAddresses || false)
127-
&& activeAccountInfo.value.btcAddresses.external.length > 0);
128-
129125
const nimExchangeRate = computed(() => exchangeRates.value[CryptoCurrency.NIM]?.[fiatCurrency.value]);
130126
const btcExchangeRate = computed(() => exchangeRates.value[CryptoCurrency.BTC]?.[fiatCurrency.value]);
131127

src/components/BtcTransactionList.vue

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,8 @@ export default defineComponent({
150150
const scrollerBuffer = 300;
151151
152152
// Height of items in pixel
153-
const { width: windowWidth } = useWindowSize();
154-
const itemSize = computed(() => windowWidth.value > 700 // Full mobile breakpoint
155-
? 72
156-
: 68, // 64px + 4px margin between items
157-
);
153+
const { isMobile } = useWindowSize();
154+
const itemSize = computed(() => isMobile.value ? 68 : 72); // mobile: 64px + 4px margin between items
158155
159156
// Get all transactions for the active addresses
160157
const txsForActiveAddress = computed(() => Object.values(btcTransactions$.transactions)

src/components/IdenticonStack.vue

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default defineComponent({
3838
},
3939
},
4040
setup() {
41-
const { activeAccountInfo, activeCurrency } = useAccountStore();
41+
const { activeCurrency, hasBitcoinAddresses } = useAccountStore();
4242
const { addressInfos, activeAddressInfo } = useAddressStore();
4343
4444
const backgroundAddresses = computed(() =>
@@ -50,10 +50,6 @@ export default defineComponent({
5050
.map((addressInfo) => addressInfo.address),
5151
);
5252
53-
const hasBitcoinAddresses = computed(() => (activeAccountInfo.value || false)
54-
&& (activeAccountInfo.value.btcAddresses || false)
55-
&& activeAccountInfo.value.btcAddresses.external.length > 0);
56-
5753
return {
5854
backgroundAddresses,
5955
hasBitcoinAddresses,

src/components/MobileActionBar.vue

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@
1818
<script lang="ts">
1919
import { defineComponent, computed } from '@vue/composition-api';
2020
import { ArrowRightSmallIcon, ScanQrCodeIcon } from '@nimiq/vue-components';
21-
import { useAddressStore } from '../stores/Address';
21+
import { AddressType, useAddressStore } from '../stores/Address';
2222
import { useAccountStore } from '../stores/Account';
2323
import { CryptoCurrency } from '../lib/Constants';
2424
import { useBtcAddressStore } from '../stores/BtcAddress';
25+
import { useWindowSize } from '../composables/useWindowSize';
26+
import { ColumnType, useActiveMobileColumn } from '../composables/useActiveMobileColumn';
2527
2628
export default defineComponent({
2729
setup(props, context) {
28-
const { activeAddressInfo } = useAddressStore();
29-
const { activeCurrency } = useAccountStore();
30+
const { activeAddressInfo, addressInfos } = useAddressStore();
31+
const { activeCurrency, activeAccountInfo, hasBitcoinAddresses } = useAccountStore();
3032
const { accountBalance } = useBtcAddressStore();
33+
const { isMobile } = useWindowSize();
34+
const { activeMobileColumn } = useActiveMobileColumn();
3135
3236
function nimOrBtc<T>(nim: T, btc: T): T {
3337
switch (activeCurrency.value) {
@@ -37,15 +41,37 @@ export default defineComponent({
3741
}
3842
}
3943
44+
const hasMultipleReceivableAddresses = computed(() => (
45+
addressInfos.value.filter(({ type }) => type === AddressType.BASIC).length > 1));
46+
4047
function receive() {
41-
context.root.$router.push(nimOrBtc<string>('/receive', '/btc-receive'));
48+
if (isMobile.value
49+
&& activeMobileColumn.value !== ColumnType.ADDRESS
50+
&& (hasMultipleReceivableAddresses.value || hasBitcoinAddresses.value)
51+
) {
52+
// redirect to the address selector
53+
context.root.$router.push('/receive');
54+
} else {
55+
context.root.$router.push(nimOrBtc('/receive/nim', '/receive/btc'));
56+
}
4257
}
4358
59+
const hasMultipleSendableAddresses = computed(() =>
60+
activeAccountInfo.value && activeAccountInfo.value.addresses.length > 1);
61+
4462
function send() {
45-
context.root.$router.push(nimOrBtc<string>('/send', '/btc-send'));
63+
if (isMobile.value
64+
&& activeMobileColumn.value !== ColumnType.ADDRESS
65+
&& (hasMultipleSendableAddresses.value || hasBitcoinAddresses.value)
66+
) {
67+
// redirect to the address selector
68+
context.root.$router.push('/send');
69+
} else {
70+
context.root.$router.push(nimOrBtc('/send/nim', '/send/btc'));
71+
}
4672
}
4773
48-
const sendDisabled = computed(() => nimOrBtc(
74+
const sendDisabled = computed(() => context.root.$route.path !== '/' && nimOrBtc(
4975
!activeAddressInfo.value || !activeAddressInfo.value.balance,
5076
!accountBalance.value,
5177
));
@@ -68,6 +94,7 @@ export default defineComponent({
6894
justify-content: space-between;
6995
align-items: center;
7096
padding: 2rem;
97+
padding-bottom: max(2rem, env(safe-area-inset-bottom));
7198
background: white;
7299
73100
display: none;

src/components/TransactionList.vue

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,8 @@ export default defineComponent({
165165
const scrollerBuffer = 300;
166166
167167
// Height of items in pixel
168-
const { width: windowWidth } = useWindowSize();
169-
const itemSize = computed(() => windowWidth.value > 700 // Full mobile breakpoint
170-
? 72
171-
: 68, // 64px + 4px margin between items
172-
);
168+
const { isMobile } = useWindowSize();
169+
const itemSize = computed(() => isMobile.value ? 68 : 72); // mobile: 64px + 4px margin between items
173170
174171
// Get all transactions for the active address
175172
const txsForActiveAddress = computed(() => Object.values(transactions$.transactions)

src/components/layouts/AccountOverview.vue

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ import { useSettingsStore } from '../../stores/Settings';
140140
export default defineComponent({
141141
name: 'account-overview',
142142
setup(props, context) {
143-
const { activeAccountInfo, activeAccountId, setActiveCurrency, activeCurrency } = useAccountStore();
143+
const {
144+
activeAccountInfo,
145+
activeAccountId,
146+
setActiveCurrency,
147+
activeCurrency,
148+
hasBitcoinAddresses,
149+
} = useAccountStore();
144150
const { accountBalance: btcAccountBalance } = useBtcAddressStore();
145151
146152
const isLegacyAccount = computed(() => (activeAccountInfo.value || false)
@@ -149,37 +155,33 @@ export default defineComponent({
149155
const canHaveMultipleAddresses = computed(() => (activeAccountInfo.value || false)
150156
&& activeAccountInfo.value.type !== AccountType.LEGACY);
151157
152-
const hasBitcoinAddresses = computed(() => (activeAccountInfo.value || false)
153-
&& (activeAccountInfo.value.btcAddresses || false)
154-
&& activeAccountInfo.value.btcAddresses.external.length > 0);
155-
156-
const { width } = useWindowSize();
158+
const { isMobile, isTablet } = useWindowSize();
157159
158160
function onAddressSelected() {
159161
setActiveCurrency(CryptoCurrency.NIM);
160162
161-
if (width.value <= 700) { // Full mobile breakpoint
163+
if (isMobile.value) {
162164
context.root.$router.push('/transactions');
163165
}
164166
}
165167
166168
function selectBitcoin() {
167169
setActiveCurrency(CryptoCurrency.BTC);
168170
169-
if (width.value <= 700) { // Full mobile breakpoint
171+
if (isMobile.value) {
170172
context.root.$router.push('/transactions');
171173
}
172174
}
173175
174176
const showFullLegacyAccountNotice = computed(() =>
175177
isLegacyAccount.value
176178
&& activeAccountInfo.value!.addresses.length === 1
177-
&& width.value > 960); // Tablet breakpoint
179+
&& !isTablet.value);
178180
179181
const showModalLegacyAccountNotice = ref(false);
180182
181183
function determineIfShowModalLegacyAccountNotice() {
182-
showModalLegacyAccountNotice.value = isLegacyAccount.value && width.value <= 960; // Tablet breakpoint
184+
showModalLegacyAccountNotice.value = isLegacyAccount.value && isTablet.value;
183185
}
184186
185187
function determineModalToShow() {

0 commit comments

Comments
 (0)