mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
feat(tab): add support for custom tabstrip (#7580)
This commit is contained in:
@ -0,0 +1,31 @@
|
|||||||
|
.custom-tabstrip {
|
||||||
|
height: 100;
|
||||||
|
vertical-align: bottom;
|
||||||
|
ios-overflow-safe-area-enabled: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabstripitem {
|
||||||
|
height: 80;
|
||||||
|
width: 80;
|
||||||
|
vertical-align: center;
|
||||||
|
horizontal-align: center;
|
||||||
|
clip-path: circle(100% at 50% 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-title {
|
||||||
|
color: white;
|
||||||
|
vertical-align: center;
|
||||||
|
horizontal-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skyblue {
|
||||||
|
background-color: skyblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gold {
|
||||||
|
background-color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olive {
|
||||||
|
background-color: olive;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import { EventData } from "tns-core-modules/data/observable";
|
||||||
|
import { Page } from "tns-core-modules/ui/page";
|
||||||
|
import { BottomNavigation } from "tns-core-modules/ui/bottom-navigation";
|
||||||
|
|
||||||
|
export function goToFirst(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <BottomNavigation>page.getViewById("bottomNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goToSecond(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <BottomNavigation>page.getViewById("bottomNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goToThird(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <BottomNavigation>page.getViewById("bottomNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 2;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
<Page>
|
||||||
|
|
||||||
|
<ActionBar title="BottomNavigation Custom TabStrip" icon="" class="action-bar">
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<GridLayout>
|
||||||
|
<GridLayout>
|
||||||
|
<BottomNavigation id="bottomNav" automationText="tabNavigation" >
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="skyblue">
|
||||||
|
<Label text="First View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="gold">
|
||||||
|
<Label text="Second View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="olive">
|
||||||
|
<Label text="Third View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
</BottomNavigation>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout columns="*, *, *" class="custom-tabstrip">
|
||||||
|
<GridLayout automationText="first-tab" col="0" class="custom-tabstripitem skyblue" tap="goToFirst">
|
||||||
|
<Label text="First" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout automationText="second-tab" col="1" class="custom-tabstripitem gold" tap="goToSecond">
|
||||||
|
<Label text="Second" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout automationText="third-tab" col="2" class="custom-tabstripitem olive" tap="goToThird">
|
||||||
|
<Label text="Third" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
</Page>
|
@ -23,6 +23,7 @@ export function loadExamples() {
|
|||||||
examples.set("font-icons", "bottom-navigation/font-icons-page");
|
examples.set("font-icons", "bottom-navigation/font-icons-page");
|
||||||
examples.set("fancy-fonts", "bottom-navigation/fancy-fonts-page");
|
examples.set("fancy-fonts", "bottom-navigation/fancy-fonts-page");
|
||||||
examples.set("css-text-transform", "bottom-navigation/bottom-navigation-css-page");
|
examples.set("css-text-transform", "bottom-navigation/bottom-navigation-css-page");
|
||||||
|
examples.set("custom-tabstrip", "bottom-navigation/custom-tabstrip-page");
|
||||||
|
|
||||||
return examples;
|
return examples;
|
||||||
}
|
}
|
||||||
|
31
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.css
Normal file
31
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.custom-tabstrip {
|
||||||
|
height: 100;
|
||||||
|
vertical-align: bottom;
|
||||||
|
ios-overflow-safe-area-enabled: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabstripitem {
|
||||||
|
height: 80;
|
||||||
|
width: 80;
|
||||||
|
vertical-align: center;
|
||||||
|
horizontal-align: center;
|
||||||
|
clip-path: circle(100% at 50% 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-title {
|
||||||
|
color: white;
|
||||||
|
vertical-align: center;
|
||||||
|
horizontal-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skyblue {
|
||||||
|
background-color: skyblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gold {
|
||||||
|
background-color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.olive {
|
||||||
|
background-color: olive;
|
||||||
|
}
|
24
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.ts
Normal file
24
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { EventData } from "tns-core-modules/data/observable";
|
||||||
|
import { Page } from "tns-core-modules/ui/page";
|
||||||
|
import { Tabs } from "tns-core-modules/ui/tabs";
|
||||||
|
|
||||||
|
export function goToFirst(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <Tabs>page.getViewById("tabsNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goToSecond(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <Tabs>page.getViewById("tabsNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function goToThird(args: EventData) {
|
||||||
|
const page = <Page>(<any>args.object).page;
|
||||||
|
const bottomNav = <Tabs>page.getViewById("tabsNav");
|
||||||
|
|
||||||
|
bottomNav.selectedIndex = 2;
|
||||||
|
}
|
41
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.xml
Normal file
41
e2e/ui-tests-app/app/tabs/custom-tabstrip-page.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<Page>
|
||||||
|
|
||||||
|
<ActionBar title="Tabs Custom TabStrip" icon="" class="action-bar">
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<GridLayout>
|
||||||
|
<GridLayout>
|
||||||
|
<Tabs id="tabsNav" automationText="tabNavigation" >
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="skyblue">
|
||||||
|
<Label text="First View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="gold">
|
||||||
|
<Label text="Second View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
<TabContentItem>
|
||||||
|
<GridLayout backgroundColor="olive">
|
||||||
|
<Label text="Third View"/>
|
||||||
|
</GridLayout>
|
||||||
|
</TabContentItem>
|
||||||
|
</Tabs>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout columns="*, *, *" class="custom-tabstrip">
|
||||||
|
<GridLayout automationText="first-tab" col="0" class="custom-tabstripitem skyblue" tap="goToFirst">
|
||||||
|
<Label text="First" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout automationText="second-tab" col="1" class="custom-tabstripitem gold" tap="goToSecond">
|
||||||
|
<Label text="Second" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<GridLayout automationText="third-tab" col="2" class="custom-tabstripitem olive" tap="goToThird">
|
||||||
|
<Label text="Third" class="custom-title"></Label>
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
</GridLayout>
|
||||||
|
</Page>
|
@ -29,6 +29,7 @@ export function loadExamples() {
|
|||||||
examples.set("font-icons", "tabs/font-icons-page");
|
examples.set("font-icons", "tabs/font-icons-page");
|
||||||
examples.set("nested-layout", "tabs/nested-layout-page");
|
examples.set("nested-layout", "tabs/nested-layout-page");
|
||||||
examples.set("nested-bottom-navigation", "tabs/nested-bottom-navigation-page");
|
examples.set("nested-bottom-navigation", "tabs/nested-bottom-navigation-page");
|
||||||
|
examples.set("custom-tabstrip", "tabs/custom-tabstrip-page");
|
||||||
|
|
||||||
return examples;
|
return examples;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-background-color`, async function () {
|
it(`${spec}-background-color`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("background-color");
|
await bottomNavigationBasePage.navigateToSample("background-color");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -55,6 +56,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
*/
|
*/
|
||||||
it(`${spec}-binding-add-items`, async function () {
|
it(`${spec}-binding-add-items`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("binding");
|
await bottomNavigationBasePage.navigateToSample("binding");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
const addTabBtn = await driver.waitForElement("add-tab");
|
const addTabBtn = await driver.waitForElement("add-tab");
|
||||||
@ -83,6 +85,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
*/
|
*/
|
||||||
it(`${spec}-binding-remove-items`, async function () {
|
it(`${spec}-binding-remove-items`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("binding");
|
await bottomNavigationBasePage.navigateToSample("binding");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
const removeTabBtn = await driver.waitForElement("remove-last-tab");
|
const removeTabBtn = await driver.waitForElement("remove-last-tab");
|
||||||
@ -115,6 +118,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-bottom-navigation`, async function () {
|
it(`${spec}-bottom-navigation`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("bottom-navigation");
|
await bottomNavigationBasePage.navigateToSample("bottom-navigation");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
const goToSecondBtn = await driver.waitForElement("goToSecond");
|
const goToSecondBtn = await driver.waitForElement("goToSecond");
|
||||||
@ -130,6 +134,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-color`, async function () {
|
it(`${spec}-color`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("color");
|
await bottomNavigationBasePage.navigateToSample("color");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -141,6 +146,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-fancy-fonts-select-tabs`, async function () {
|
it(`${spec}-fancy-fonts-select-tabs`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
for (let index = 1; index < 4; index++) {
|
for (let index = 1; index < 4; index++) {
|
||||||
@ -154,6 +160,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-fancy-fonts-selected-index`, async function () {
|
it(`${spec}-fancy-fonts-selected-index`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
|
|
||||||
let selectSecondTabFromCodeBehind = await driver.waitForElement("selectSecondTab");
|
let selectSecondTabFromCodeBehind = await driver.waitForElement("selectSecondTab");
|
||||||
logInfo(`Click on "select second tab button"`);
|
logInfo(`Click on "select second tab button"`);
|
||||||
@ -186,6 +193,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-fancy-fonts-change-orientation`, async function () {
|
it(`${spec}-fancy-fonts-change-orientation`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
await bottomNavigationBasePage.navigateToSample("fancy-fonts");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.setOrientation(DeviceOrientation.LANDSCAPE);
|
await driver.setOrientation(DeviceOrientation.LANDSCAPE);
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
@ -212,6 +220,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-font-icons`, async function () {
|
it(`${spec}-font-icons`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("font-icons");
|
await bottomNavigationBasePage.navigateToSample("font-icons");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -227,6 +236,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-icon-change`, async function () {
|
it(`${spec}-icon-change`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("icon-change");
|
await bottomNavigationBasePage.navigateToSample("icon-change");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
@ -240,6 +250,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-icon-title-placment`, async function () {
|
it(`${spec}-icon-title-placment`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("icon-title-placement");
|
await bottomNavigationBasePage.navigateToSample("icon-title-placement");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
await bottomNavigationBasePage.navigateBackToSuitMainPage();
|
await bottomNavigationBasePage.navigateBackToSuitMainPage();
|
||||||
@ -247,6 +258,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-5470-issue`, async function () {
|
it(`${spec}-5470-issue`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("issue-5470");
|
await bottomNavigationBasePage.navigateToSample("issue-5470");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -258,6 +270,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-text-transform`, async function () {
|
it(`${spec}-text-transform`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("text-transform");
|
await bottomNavigationBasePage.navigateToSample("text-transform");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -269,6 +282,7 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${spec}-fonts`, async function () {
|
it(`${spec}-fonts`, async function () {
|
||||||
await bottomNavigationBasePage.navigateToSample("text-transform");
|
await bottomNavigationBasePage.navigateToSample("text-transform");
|
||||||
|
await bottomNavigationBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await bottomNavigationBasePage.tabOnItem(1);
|
await bottomNavigationBasePage.tabOnItem(1);
|
||||||
@ -277,4 +291,16 @@ describe(`${suite}-${spec}-suite`, async function () {
|
|||||||
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
await bottomNavigationBasePage.navigateBackToSuitMainPage();
|
await bottomNavigationBasePage.navigateBackToSuitMainPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`${spec}-custom-tabstrip`, async function () {
|
||||||
|
await bottomNavigationBasePage.navigateToSample("custom-tabstrip");
|
||||||
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
|
const secondTab = await driver.waitForElement("second-tab");
|
||||||
|
await secondTab.tap();
|
||||||
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
|
await bottomNavigationBasePage.navigateBackToSuitMainPage();
|
||||||
|
});
|
||||||
});
|
});
|
@ -21,7 +21,6 @@ export abstract class TabNavigationBasePage extends PageObjectBaseModel {
|
|||||||
|
|
||||||
async navigateToSample(sample: string) {
|
async navigateToSample(sample: string) {
|
||||||
await super.navigateToSample(sample);
|
await super.navigateToSample(sample);
|
||||||
await this.refreshTabItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshTabItems() {
|
async refreshTabItems() {
|
||||||
|
@ -39,6 +39,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-background-color`, async function () {
|
it(`${imagePrefix}-background-color`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("background-color");
|
await tabsViewBasePage.navigateToSample("background-color");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -52,6 +53,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
// not all css is applied.
|
// not all css is applied.
|
||||||
it(`${imagePrefix}-color`, async function () {
|
it(`${imagePrefix}-color`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("color");
|
await tabsViewBasePage.navigateToSample("color");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -63,6 +65,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-font`, async function () {
|
it(`${imagePrefix}-font`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("font");
|
await tabsViewBasePage.navigateToSample("font");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -78,6 +81,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-font-icons`, async function () {
|
it(`${imagePrefix}-font-icons`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("font-icons");
|
await tabsViewBasePage.navigateToSample("font-icons");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -98,6 +102,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-highlight-color`, async function () {
|
it(`${imagePrefix}-highlight-color`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("highlight-color");
|
await tabsViewBasePage.navigateToSample("highlight-color");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -110,6 +115,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-icon-change`, async function () {
|
it(`${imagePrefix}-icon-change`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("icon-change");
|
await tabsViewBasePage.navigateToSample("icon-change");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
|
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
@ -126,6 +132,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-icon-title-placment`, async function () {
|
it(`${imagePrefix}-icon-title-placment`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("icon-title-placement");
|
await tabsViewBasePage.navigateToSample("icon-title-placement");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
await tabsViewBasePage.navigateBackToSuitMainPage();
|
await tabsViewBasePage.navigateBackToSuitMainPage();
|
||||||
@ -133,6 +140,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-issue-5470`, async function () {
|
it(`${imagePrefix}-issue-5470`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("issue-5470");
|
await tabsViewBasePage.navigateToSample("issue-5470");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.tabOnItem(1);
|
await tabsViewBasePage.tabOnItem(1);
|
||||||
@ -144,6 +152,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-strip-item`, async function () {
|
it(`${imagePrefix}-strip-item`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("strip-item");
|
await tabsViewBasePage.navigateToSample("strip-item");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
@ -155,6 +164,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
await tabsViewBasePage.navigateToSample("swipe-disabled");
|
await tabsViewBasePage.navigateToSample("swipe-disabled");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
|
|
||||||
await tabsViewBasePage.swipeRightToLeft();
|
await tabsViewBasePage.swipeRightToLeft();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
@ -166,6 +176,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-swipe`, async function () {
|
it(`${imagePrefix}-swipe`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("tabs");
|
await tabsViewBasePage.navigateToSample("tabs");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await tabsViewBasePage.swipeRightToLeft();
|
await tabsViewBasePage.swipeRightToLeft();
|
||||||
|
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
@ -185,6 +196,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
await tabsViewBasePage.navigateToSample("tabs-binding");
|
await tabsViewBasePage.navigateToSample("tabs-binding");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
const addTabBtn = await driver.waitForElement("add-tab");
|
const addTabBtn = await driver.waitForElement("add-tab");
|
||||||
@ -216,6 +228,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
await tabsViewBasePage.navigateToSample("tabs-binding");
|
await tabsViewBasePage.navigateToSample("tabs-binding");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
const removeTabBtn = await driver.waitForElement("remove-last-tab");
|
const removeTabBtn = await driver.waitForElement("remove-last-tab");
|
||||||
@ -248,6 +261,7 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
|
|
||||||
it(`${imagePrefix}-text-transform`, async function () {
|
it(`${imagePrefix}-text-transform`, async function () {
|
||||||
await tabsViewBasePage.navigateToSample("text-transform");
|
await tabsViewBasePage.navigateToSample("text-transform");
|
||||||
|
await tabsViewBasePage.refreshTabItems();
|
||||||
await driver.imageHelper.compareScreen();
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
await tabsViewBasePage.refreshTabItems();
|
await tabsViewBasePage.refreshTabItems();
|
||||||
@ -257,4 +271,16 @@ describe(`${imagePrefix}-suite`, async function () {
|
|||||||
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
await tabsViewBasePage.navigateBackToSuitMainPage();
|
await tabsViewBasePage.navigateBackToSuitMainPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`${imagePrefix}-custom-tabstrip`, async function () {
|
||||||
|
await tabsViewBasePage.navigateToSample("custom-tabstrip");
|
||||||
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
|
const secondTab = await driver.waitForElement("second-tab");
|
||||||
|
await secondTab.tap();
|
||||||
|
await driver.imageHelper.compareScreen();
|
||||||
|
|
||||||
|
assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
|
||||||
|
await tabsViewBasePage.navigateBackToSuitMainPage();
|
||||||
|
});
|
||||||
});
|
});
|
@ -230,6 +230,7 @@ export class BottomNavigationTest extends UITest<BottomNavigation> {
|
|||||||
public test_when_selecting_tab_natively_selectedIndex_is_updated_properly = function () {
|
public test_when_selecting_tab_natively_selectedIndex_is_updated_properly = function () {
|
||||||
var tabView = this.testView;
|
var tabView = this.testView;
|
||||||
tabView.items = this._createContentItems(2);
|
tabView.items = this._createContentItems(2);
|
||||||
|
tabView.tabStrip = this._createTabStrip(2);
|
||||||
this.waitUntilTestElementIsLoaded();
|
this.waitUntilTestElementIsLoaded();
|
||||||
|
|
||||||
var expectedValue = 1;
|
var expectedValue = 1;
|
||||||
@ -245,6 +246,7 @@ export class BottomNavigationTest extends UITest<BottomNavigation> {
|
|||||||
public test_when_selecting_tab_natively_selectedIndexChangedEvent_is_raised = function () {
|
public test_when_selecting_tab_natively_selectedIndexChangedEvent_is_raised = function () {
|
||||||
var tabView = this.testView;
|
var tabView = this.testView;
|
||||||
tabView.items = this._createContentItems(5);
|
tabView.items = this._createContentItems(5);
|
||||||
|
tabView.tabStrip = this._createTabStrip(5);
|
||||||
this.waitUntilTestElementIsLoaded();
|
this.waitUntilTestElementIsLoaded();
|
||||||
|
|
||||||
var expectedOldIndex = 3;
|
var expectedOldIndex = 3;
|
||||||
|
@ -315,7 +315,7 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
|
|
||||||
this._bottomNavigationBar = (<any>nativeView).bottomNavigationBar;
|
this._bottomNavigationBar = (<any>nativeView).bottomNavigationBar;
|
||||||
(<any>this._bottomNavigationBar).owner = this;
|
(<any>this._bottomNavigationBar).owner = this;
|
||||||
|
|
||||||
if (this.tabStrip) {
|
if (this.tabStrip) {
|
||||||
this.tabStrip.setNativeView(this._bottomNavigationBar);
|
this.tabStrip.setNativeView(this._bottomNavigationBar);
|
||||||
}
|
}
|
||||||
@ -362,8 +362,12 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
public onLoaded(): void {
|
public onLoaded(): void {
|
||||||
super.onLoaded();
|
super.onLoaded();
|
||||||
|
|
||||||
const items = this.tabStrip ? this.tabStrip.items : null;
|
if (this.tabStrip) {
|
||||||
this.setTabStripItems(items);
|
this.setTabStripItems(this.tabStrip.items);
|
||||||
|
} else {
|
||||||
|
// manually set the visibility, so that the grid layout remeasures
|
||||||
|
this._bottomNavigationBar.setVisibility(android.view.View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._attachedToWindow) {
|
if (this._attachedToWindow) {
|
||||||
this.changeTab(this.selectedIndex);
|
this.changeTab(this.selectedIndex);
|
||||||
@ -386,7 +390,9 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
public onUnloaded(): void {
|
public onUnloaded(): void {
|
||||||
super.onUnloaded();
|
super.onUnloaded();
|
||||||
|
|
||||||
this.setTabStripItems(null);
|
if (this.tabStrip) {
|
||||||
|
this.setTabStripItems(null);
|
||||||
|
}
|
||||||
|
|
||||||
const fragmentToDetach = this._currentFragment;
|
const fragmentToDetach = this._currentFragment;
|
||||||
if (fragmentToDetach) {
|
if (fragmentToDetach) {
|
||||||
@ -637,7 +643,11 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
// traceWrite("TabView this._viewPager.setCurrentItem(" + value + ", " + smoothScroll + ");", traceCategory);
|
// traceWrite("TabView this._viewPager.setCurrentItem(" + value + ", " + smoothScroll + ");", traceCategory);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
this._bottomNavigationBar.setSelectedPosition(value);
|
if (this.tabStrip) {
|
||||||
|
this._bottomNavigationBar.setSelectedPosition(value);
|
||||||
|
} else {
|
||||||
|
this.changeTab(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[itemsProperty.getDefault](): TabContentItem[] {
|
[itemsProperty.getDefault](): TabContentItem[] {
|
||||||
|
@ -243,6 +243,9 @@ export class BottomNavigation extends TabNavigationBase {
|
|||||||
super.initNativeView();
|
super.initNativeView();
|
||||||
this._delegate = UITabBarControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
this._delegate = UITabBarControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
||||||
this._moreNavigationControllerDelegate = UINavigationControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
this._moreNavigationControllerDelegate = UINavigationControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
||||||
|
if (!this.tabStrip) {
|
||||||
|
this.viewController.tabBar.hidden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disposeNativeView() {
|
disposeNativeView() {
|
||||||
|
@ -493,7 +493,10 @@ export class Tabs extends TabsBase {
|
|||||||
super.onLoaded();
|
super.onLoaded();
|
||||||
|
|
||||||
this.setItems((<any>this.items));
|
this.setItems((<any>this.items));
|
||||||
this.setTabStripItems(this.tabStrip.items);
|
|
||||||
|
if (this.tabStrip) {
|
||||||
|
this.setTabStripItems(this.tabStrip.items);
|
||||||
|
}
|
||||||
|
|
||||||
// this.setAdapterItems(this.items);
|
// this.setAdapterItems(this.items);
|
||||||
}
|
}
|
||||||
|
@ -76,24 +76,27 @@ class UIPageViewControllerImpl extends UIPageViewController {
|
|||||||
|
|
||||||
public viewDidLoad(): void {
|
public viewDidLoad(): void {
|
||||||
const owner = this._owner.get();
|
const owner = this._owner.get();
|
||||||
const tabBarItems = owner.tabBarItems;
|
|
||||||
const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds);
|
|
||||||
|
|
||||||
if (tabBarItems && tabBarItems.length) {
|
if (owner.tabStrip) {
|
||||||
tabBar.items = NSArray.arrayWithArray(tabBarItems);
|
const tabBarItems = owner.tabBarItems;
|
||||||
|
const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds);
|
||||||
|
|
||||||
|
if (tabBarItems && tabBarItems.length) {
|
||||||
|
tabBar.items = NSArray.arrayWithArray(tabBarItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner));
|
||||||
|
tabBar.tintColor = UIColor.blueColor;
|
||||||
|
tabBar.barTintColor = UIColor.whiteColor;
|
||||||
|
tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal);
|
||||||
|
tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected);
|
||||||
|
tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin;
|
||||||
|
tabBar.alignment = MDCTabBarAlignment.Leading;
|
||||||
|
tabBar.sizeToFit();
|
||||||
|
|
||||||
|
this.tabBar = tabBar;
|
||||||
|
this.view.addSubview(tabBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner));
|
|
||||||
tabBar.tintColor = UIColor.blueColor;
|
|
||||||
tabBar.barTintColor = UIColor.whiteColor;
|
|
||||||
tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal);
|
|
||||||
tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected);
|
|
||||||
tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin;
|
|
||||||
tabBar.alignment = MDCTabBarAlignment.Leading;
|
|
||||||
tabBar.sizeToFit();
|
|
||||||
|
|
||||||
this.tabBar = tabBar;
|
|
||||||
this.view.addSubview(tabBar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public viewWillAppear(animated: boolean): void {
|
public viewWillAppear(animated: boolean): void {
|
||||||
@ -116,40 +119,39 @@ class UIPageViewControllerImpl extends UIPageViewController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabsPosition = owner.tabsPosition;
|
let scrollViewTop = 0;
|
||||||
const parent = owner.parent;
|
let scrollViewHeight = this.view.bounds.size.height + this.view.safeAreaInsets.bottom;
|
||||||
|
|
||||||
let tabBarTop = this.view.safeAreaInsets.top;
|
if (owner.tabStrip) {
|
||||||
let tabBarHeight = this.tabBar.frame.size.height;
|
scrollViewTop = this.tabBar.frame.size.height;
|
||||||
let scrollViewTop = this.tabBar.frame.size.height;
|
scrollViewHeight = this.view.bounds.size.height - this.tabBar.frame.size.height + this.view.safeAreaInsets.bottom;
|
||||||
let scrollViewHeight = this.view.bounds.size.height - this.tabBar.frame.size.height;
|
let tabBarTop = this.view.safeAreaInsets.top;
|
||||||
|
let tabBarHeight = this.tabBar.frame.size.height;
|
||||||
|
|
||||||
if (parent) {
|
const tabsPosition = owner.tabsPosition;
|
||||||
// TODO: Figure out a better way to handle ViewController nesting/Safe Area nesting
|
if (tabsPosition === "bottom") {
|
||||||
tabBarTop = Math.max(this.view.safeAreaInsets.top, owner.parent.nativeView.safeAreaInsets.top);
|
tabBarTop = this.view.frame.size.height - this.tabBar.frame.size.height - this.view.safeAreaInsets.bottom;
|
||||||
|
scrollViewTop = this.view.frame.origin.y;
|
||||||
|
scrollViewHeight = this.view.frame.size.height - this.view.safeAreaInsets.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = owner.parent;
|
||||||
|
if (parent) {
|
||||||
|
// TODO: Figure out a better way to handle ViewController nesting/Safe Area nesting
|
||||||
|
tabBarTop = Math.max(tabBarTop, owner.parent.nativeView.safeAreaInsets.top);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tabBar.frame = CGRectMake(this.view.safeAreaInsets.left, tabBarTop, this.tabBar.frame.size.width, tabBarHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tabsPosition === "bottom") {
|
|
||||||
tabBarTop = this.view.frame.size.height - this.tabBar.frame.size.height - this.view.safeAreaInsets.bottom;
|
|
||||||
scrollViewTop = this.view.frame.origin.y;
|
|
||||||
scrollViewHeight = this.view.frame.size.height - this.view.safeAreaInsets.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tabBar.frame = CGRectMake(this.view.safeAreaInsets.left, tabBarTop, this.tabBar.frame.size.width, tabBarHeight);
|
|
||||||
|
|
||||||
const subViews: NSArray<UIView> = this.view.subviews;
|
const subViews: NSArray<UIView> = this.view.subviews;
|
||||||
let scrollView: UIScrollView = null;
|
let scrollView: UIScrollView = null;
|
||||||
let mdcBar: MDCTabBar = null;
|
|
||||||
|
|
||||||
for (let i = 0; i < subViews.count; i++) {
|
for (let i = 0; i < subViews.count; i++) {
|
||||||
const view: UIView = subViews[i];
|
const view: UIView = subViews[i];
|
||||||
if (view instanceof UIScrollView) {
|
if (view instanceof UIScrollView) {
|
||||||
scrollView = <UIScrollView>view;
|
scrollView = <UIScrollView>view;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view instanceof MDCTabBar) {
|
|
||||||
mdcBar = <MDCTabBar>view;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollView) {
|
if (scrollView) {
|
||||||
@ -489,7 +491,10 @@ export class Tabs extends TabsBase {
|
|||||||
|
|
||||||
// this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); // .alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null); // UITabBarControllerImpl.initWithOwner(new WeakRef(this));
|
// this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); // .alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null); // UITabBarControllerImpl.initWithOwner(new WeakRef(this));
|
||||||
this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); //alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null);;
|
this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); //alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null);;
|
||||||
this.nativeViewProtected = this._ios.view;
|
}
|
||||||
|
|
||||||
|
createNativeView() {
|
||||||
|
return this._ios.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
initNativeView() {
|
initNativeView() {
|
||||||
|
Reference in New Issue
Block a user