feat: implement magic link sign in (#5036)

This commit is contained in:
Lucas.Xu 2024-04-11 16:33:28 +08:00 committed by GitHub
parent b7b4ea2da1
commit 1597f7d94c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
81 changed files with 599 additions and 473 deletions

View File

@ -32,7 +32,7 @@ void main() {
); );
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr()); tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
// reanme the name of the anon user // reanme the name of the anon user

View File

@ -18,7 +18,7 @@ void main() {
group('board add row test:', () { group('board add row test:', () {
testWidgets('from header', (tester) async { testWidgets('from header', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
@ -61,7 +61,7 @@ void main() {
testWidgets('from footer', (tester) async { testWidgets('from footer', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);

View File

@ -15,7 +15,7 @@ void main() {
testWidgets('move row to another group', (tester) async { testWidgets('move row to another group', (tester) async {
const card1Name = 'Card 1'; const card1Name = 'Card 1';
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final card1 = find.ancestor( final card1 = find.ancestor(

View File

@ -16,7 +16,7 @@ void main() {
group('board group options:', () { group('board group options:', () {
testWidgets('expand/collapse hidden groups', (tester) async { testWidgets('expand/collapse hidden groups', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s); final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s);
@ -45,7 +45,7 @@ void main() {
testWidgets('hide first group, and show it again', (tester) async { testWidgets('hide first group, and show it again', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// Tap the options of the first group // Tap the options of the first group
@ -81,7 +81,7 @@ void main() {
testWidgets('delete a group', (tester) async { testWidgets('delete a group', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4); expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4);

View File

@ -7,8 +7,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
import '../../shared/database_test_op.dart'; import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -16,7 +16,7 @@ void main() {
group('board row test', () { group('board row test', () {
testWidgets('delete item in ToDo card', (tester) async { testWidgets('delete item in ToDo card', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1'; const name = 'Card 1';
@ -34,7 +34,7 @@ void main() {
testWidgets('duplicate item in ToDo card', (tester) async { testWidgets('duplicate item in ToDo card', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1'; const name = 'Card 1';
@ -52,7 +52,7 @@ void main() {
testWidgets('add new group', (tester) async { testWidgets('add new group', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// assert number of groups // assert number of groups

View File

@ -14,7 +14,7 @@ void main() {
group('calendar', () { group('calendar', () {
testWidgets('update calendar layout', (tester) async { testWidgets('update calendar layout', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar, layout: ViewLayoutPB.Calendar,
@ -36,7 +36,7 @@ void main() {
testWidgets('calendar start from day setting', (tester) async { testWidgets('calendar start from day setting', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create calendar view // Create calendar view
const name = 'calendar'; const name = 'calendar';
@ -69,7 +69,7 @@ void main() {
testWidgets('creating and editing calendar events', (tester) async { testWidgets('creating and editing calendar events', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create the calendar view // Create the calendar view
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -153,7 +153,7 @@ void main() {
const customTitle = "EventTitleCustom"; const customTitle = "EventTitleCustom";
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create the calendar view // Create the calendar view
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -194,7 +194,7 @@ void main() {
testWidgets('rescheduling events', (tester) async { testWidgets('rescheduling events', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create the calendar view // Create the calendar view
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(

View File

@ -13,7 +13,7 @@ void main() {
group('edit grid cell:', () { group('edit grid cell:', () {
testWidgets('text', (tester) async { testWidgets('text', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -36,7 +36,7 @@ void main() {
// multiple text cell // multiple text cell
testWidgets('multiple text cells', (tester) async { testWidgets('multiple text cells', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
name: 'my grid', name: 'my grid',
layout: ViewLayoutPB.Grid, layout: ViewLayoutPB.Grid,
@ -74,7 +74,7 @@ void main() {
testWidgets('number', (tester) async { testWidgets('number', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -132,7 +132,7 @@ void main() {
testWidgets('checkbox', (tester) async { testWidgets('checkbox', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -150,7 +150,7 @@ void main() {
testWidgets('created time', (tester) async { testWidgets('created time', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -168,7 +168,7 @@ void main() {
testWidgets('last modified time', (tester) async { testWidgets('last modified time', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -186,7 +186,7 @@ void main() {
testWidgets('date time', (tester) async { testWidgets('date time', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -282,7 +282,7 @@ void main() {
testWidgets('single select', (tester) async { testWidgets('single select', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
const fieldType = FieldType.SingleSelect; const fieldType = FieldType.SingleSelect;
@ -361,7 +361,7 @@ void main() {
]; ];
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -444,7 +444,7 @@ void main() {
testWidgets('checklist', (tester) async { testWidgets('checklist', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -13,7 +13,7 @@ void main() {
group('database field settings', () { group('database field settings', () {
testWidgets('field visibility', (tester) async { testWidgets('field visibility', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Grid); await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Grid);

View File

@ -17,7 +17,7 @@ void main() {
group('grid field editor:', () { group('grid field editor:', () {
testWidgets('rename existing field', (tester) async { testWidgets('rename existing field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -34,7 +34,7 @@ void main() {
testWidgets('update field type of existing field', (tester) async { testWidgets('update field type of existing field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -50,7 +50,7 @@ void main() {
testWidgets('create a field and rename it', (tester) async { testWidgets('create a field and rename it', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new grid // create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -65,7 +65,7 @@ void main() {
testWidgets('delete field', (tester) async { testWidgets('delete field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -85,7 +85,7 @@ void main() {
testWidgets('duplicate field', (tester) async { testWidgets('duplicate field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -105,7 +105,7 @@ void main() {
testWidgets('insert field on either side of a field', (tester) async { testWidgets('insert field on either side of a field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -128,7 +128,7 @@ void main() {
testWidgets('create checklist field', (tester) async { testWidgets('create checklist field', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -148,7 +148,7 @@ void main() {
testWidgets('create list of fields', (tester) async { testWidgets('create list of fields', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -180,7 +180,7 @@ void main() {
testWidgets('field types with empty type option editor', (tester) async { testWidgets('field types with empty type option editor', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -212,7 +212,7 @@ void main() {
testWidgets('number field type option', (tester) async { testWidgets('number field type option', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage)); await tester.scrollToRight(find.byType(GridPage));
@ -258,7 +258,7 @@ void main() {
testWidgets('add option', (tester) async { testWidgets('add option', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid, layout: ViewLayoutPB.Grid,
@ -286,7 +286,7 @@ void main() {
testWidgets('date time field type options', (tester) async { testWidgets('date time field type options', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage)); await tester.scrollToRight(find.byType(GridPage));

View File

@ -14,7 +14,7 @@ void main() {
group('reminder in database', () { group('reminder in database', () {
testWidgets('add date field and add reminder', (tester) async { testWidgets('add date field and add reminder', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -68,7 +68,7 @@ void main() {
testWidgets('navigate from reminder to open row', (tester) async { testWidgets('navigate from reminder to open row', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -135,7 +135,7 @@ void main() {
'toggle include time sets reminder option correctly', 'toggle include time sets reminder option correctly',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid, layout: ViewLayoutPB.Grid,

View File

@ -18,7 +18,7 @@ void main() {
group('grid row detail page:', () { group('grid row detail page:', () {
testWidgets('opens', (tester) async { testWidgets('opens', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -35,7 +35,7 @@ void main() {
testWidgets('add emoji', (tester) async { testWidgets('add emoji', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -54,7 +54,7 @@ void main() {
testWidgets('update emoji', (tester) async { testWidgets('update emoji', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -81,7 +81,7 @@ void main() {
testWidgets('remove emoji', (tester) async { testWidgets('remove emoji', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -102,7 +102,7 @@ void main() {
testWidgets('create list of fields', (tester) async { testWidgets('create list of fields', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -136,7 +136,7 @@ void main() {
testWidgets('change order of fields and cells', (tester) async { testWidgets('change order of fields and cells', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -169,7 +169,7 @@ void main() {
testWidgets('hide and show hidden fields', (tester) async { testWidgets('hide and show hidden fields', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -218,7 +218,7 @@ void main() {
testWidgets('update the contents of the document and re-open it', testWidgets('update the contents of the document and re-open it',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -258,7 +258,7 @@ void main() {
'check if the title wraps properly when a long text is inserted', 'check if the title wraps properly when a long text is inserted',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -297,7 +297,7 @@ void main() {
testWidgets('delete row', (tester) async { testWidgets('delete row', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -314,7 +314,7 @@ void main() {
testWidgets('duplicate row', (tester) async { testWidgets('duplicate row', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// Create a new grid // Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -11,7 +11,7 @@ void main() {
group('grid', () { group('grid', () {
testWidgets('create row of the grid', (tester) async { testWidgets('create row of the grid', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid(); await tester.tapCreateRowButtonInGrid();
@ -23,7 +23,7 @@ void main() {
testWidgets('create row from row menu of the grid', (tester) async { testWidgets('create row from row menu of the grid', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -38,7 +38,7 @@ void main() {
testWidgets('delete row of the grid', (tester) async { testWidgets('delete row of the grid', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid(); await tester.hoverOnFirstRowOfGrid();
@ -55,7 +55,7 @@ void main() {
testWidgets('check number of row indicator in the initial grid', testWidgets('check number of row indicator in the initial grid',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -12,7 +12,7 @@ void main() {
group('grid', () { group('grid', () {
testWidgets('update layout', (tester) async { testWidgets('update layout', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -29,7 +29,7 @@ void main() {
testWidgets('update layout multiple times', (tester) async { testWidgets('update layout multiple times', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -12,7 +12,7 @@ void main() {
group('database', () { group('database', () {
testWidgets('create linked view', (tester) async { testWidgets('create linked view', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -33,7 +33,7 @@ void main() {
testWidgets('rename and delete linked view', (tester) async { testWidgets('rename and delete linked view', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -58,7 +58,7 @@ void main() {
testWidgets('delete the last database view', (tester) async { testWidgets('delete the last database view', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -14,7 +14,7 @@ void main() {
group('document alignment', () { group('document alignment', () {
testWidgets('edit alignment in toolbar', (tester) async { testWidgets('edit alignment in toolbar', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final selection = Selection.single( final selection = Selection.single(
path: [0], path: [0],
@ -48,7 +48,7 @@ void main() {
testWidgets('edit alignment using shortcut', (tester) async { testWidgets('edit alignment using shortcut', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// click the first line of the readme // click the first line of the readme
await tester.editor.tapLineOfEditorAt(0); await tester.editor.tapLineOfEditorAt(0);

View File

@ -15,7 +15,7 @@ void main() {
group('paste in codeblock', () { group('paste in codeblock', () {
testWidgets('paste multiple lines in codeblock', (tester) async { testWidgets('paste multiple lines in codeblock', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();

View File

@ -304,7 +304,7 @@ extension on WidgetTester {
(String, Uint8List?)? image, (String, Uint8List?)? image,
}) async { }) async {
await initializeAppFlowy(); await initializeAppFlowy();
await tapGoButton(); await tapAnonymousSignInButton();
// create a new document // create a new document
await createNewPageWithNameUnderParent(); await createNewPageWithNameUnderParent();

View File

@ -14,7 +14,7 @@ void main() {
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
@ -30,7 +30,7 @@ void main() {
testWidgets('delete the readme page and restore it', (tester) async { testWidgets('delete the readme page and restore it', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// delete the readme page // delete the readme page
await tester.hoverOnPageName( await tester.hoverOnPageName(
@ -54,7 +54,7 @@ void main() {
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// delete the readme page // delete the readme page
await tester.hoverOnPageName( await tester.hoverOnPageName(

View File

@ -15,7 +15,7 @@ void main() {
group('insert inline document reference', () { group('insert inline document reference', () {
testWidgets('insert by slash menu', (tester) async { testWidgets('insert by slash menu', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final name = await createDocumentToReference(tester); final name = await createDocumentToReference(tester);
@ -42,7 +42,7 @@ void main() {
testWidgets('insert by `[[` character shortcut', (tester) async { testWidgets('insert by `[[` character shortcut', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final name = await createDocumentToReference(tester); final name = await createDocumentToReference(tester);
@ -62,7 +62,7 @@ void main() {
testWidgets('insert by `+` character shortcut', (tester) async { testWidgets('insert by `+` character shortcut', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final name = await createDocumentToReference(tester); final name = await createDocumentToReference(tester);

View File

@ -12,7 +12,7 @@ void main() {
'click + to add a block after current selection, and click + and option key to add a block before current selection', 'click + to add a block after current selection, and click + and option key to add a block before current selection',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
var editorState = tester.editor.getCurrentEditorState(); var editorState = tester.editor.getCurrentEditorState();
expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isNotEmpty); expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isNotEmpty);

View File

@ -13,7 +13,7 @@ void main() {
(tester) async { (tester) async {
// combine the two tests into one to avoid the time-consuming process of initializing the app // combine the two tests into one to avoid the time-consuming process of initializing the app
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final selection = Selection.single( final selection = Selection.single(
path: [0], path: [0],

View File

@ -16,7 +16,7 @@ void main() {
group('cover image', () { group('cover image', () {
testWidgets('document cover tests', (tester) async { testWidgets('document cover tests', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
tester.expectToSeeNoDocumentCover(); tester.expectToSeeNoDocumentCover();
@ -53,7 +53,7 @@ void main() {
testWidgets('document icon tests', (tester) async { testWidgets('document icon tests', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
tester.expectToSeeDocumentIcon('⭐️'); tester.expectToSeeDocumentIcon('⭐️');
@ -86,7 +86,7 @@ void main() {
testWidgets('icon and cover at the same time', (tester) async { testWidgets('icon and cover at the same time', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
tester.expectToSeeDocumentIcon('⭐️'); tester.expectToSeeDocumentIcon('⭐️');
tester.expectToSeeNoDocumentCover(); tester.expectToSeeNoDocumentCover();
@ -110,7 +110,7 @@ void main() {
testWidgets('shuffle icon', (tester) async { testWidgets('shuffle icon', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.editor.tapGettingStartedIcon(); await tester.editor.tapGettingStartedIcon();
@ -123,7 +123,7 @@ void main() {
testWidgets('change skin tone', (tester) async { testWidgets('change skin tone', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.editor.tapGettingStartedIcon(); await tester.editor.tapGettingStartedIcon();

View File

@ -20,7 +20,7 @@ void main() {
group('database view in document', () { group('database view in document', () {
testWidgets('insert a referenced grid', (tester) async { testWidgets('insert a referenced grid', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Grid); await insertReferenceDatabase(tester, ViewLayoutPB.Grid);
@ -48,7 +48,7 @@ void main() {
testWidgets('insert a referenced board', (tester) async { testWidgets('insert a referenced board', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Board); await insertReferenceDatabase(tester, ViewLayoutPB.Board);
@ -64,7 +64,7 @@ void main() {
testWidgets('insert a referenced calendar', (tester) async { testWidgets('insert a referenced calendar', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertReferenceDatabase(tester, ViewLayoutPB.Calendar); await insertReferenceDatabase(tester, ViewLayoutPB.Calendar);
@ -80,7 +80,7 @@ void main() {
testWidgets('create a grid inside a document', (tester) async { testWidgets('create a grid inside a document', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await createInlineDatabase(tester, ViewLayoutPB.Grid); await createInlineDatabase(tester, ViewLayoutPB.Grid);
@ -96,7 +96,7 @@ void main() {
testWidgets('create a board inside a document', (tester) async { testWidgets('create a board inside a document', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await createInlineDatabase(tester, ViewLayoutPB.Board); await createInlineDatabase(tester, ViewLayoutPB.Board);
@ -112,7 +112,7 @@ void main() {
testWidgets('create a calendar inside a document', (tester) async { testWidgets('create a calendar inside a document', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await createInlineDatabase(tester, ViewLayoutPB.Calendar); await createInlineDatabase(tester, ViewLayoutPB.Calendar);

View File

@ -32,7 +32,7 @@ void main() {
group('image block in document', () { group('image block in document', () {
testWidgets('insert an image from local file', (tester) async { testWidgets('insert an image from local file', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -80,7 +80,7 @@ void main() {
testWidgets('insert an image from network', (tester) async { testWidgets('insert an image from network', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -133,7 +133,7 @@ void main() {
testWidgets('insert an image from unsplash', (tester) async { testWidgets('insert an image from unsplash', (tester) async {
await runWithNetworkImages(() async { await runWithNetworkImages(() async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(

View File

@ -16,7 +16,7 @@ void main() {
group('inline math equation in document', () { group('inline math equation in document', () {
testWidgets('insert an inline math equation', (tester) async { testWidgets('insert an inline math equation', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -61,7 +61,7 @@ void main() {
testWidgets('remove the inline math equation format', (tester) async { testWidgets('remove the inline math equation format', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(

View File

@ -13,7 +13,7 @@ void main() {
group('inline page view in document', () { group('inline page view in document', () {
testWidgets('insert a inline page - grid', (tester) async { testWidgets('insert a inline page - grid', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertInlinePage(tester, ViewLayoutPB.Grid); await insertInlinePage(tester, ViewLayoutPB.Grid);
@ -24,7 +24,7 @@ void main() {
testWidgets('insert a inline page - board', (tester) async { testWidgets('insert a inline page - board', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertInlinePage(tester, ViewLayoutPB.Board); await insertInlinePage(tester, ViewLayoutPB.Board);
@ -35,7 +35,7 @@ void main() {
testWidgets('insert a inline page - calendar', (tester) async { testWidgets('insert a inline page - calendar', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertInlinePage(tester, ViewLayoutPB.Calendar); await insertInlinePage(tester, ViewLayoutPB.Calendar);
@ -46,7 +46,7 @@ void main() {
testWidgets('insert a inline page - document', (tester) async { testWidgets('insert a inline page - document', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await insertInlinePage(tester, ViewLayoutPB.Document); await insertInlinePage(tester, ViewLayoutPB.Document);
@ -57,7 +57,7 @@ void main() {
testWidgets('insert a inline page and rename it', (tester) async { testWidgets('insert a inline page and rename it', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final pageName = await insertInlinePage(tester, ViewLayoutPB.Document); final pageName = await insertInlinePage(tester, ViewLayoutPB.Document);
@ -76,7 +76,7 @@ void main() {
testWidgets('insert a inline page and delete it', (tester) async { testWidgets('insert a inline page and delete it', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final pageName = await insertInlinePage(tester, ViewLayoutPB.Grid); final pageName = await insertInlinePage(tester, ViewLayoutPB.Grid);

View File

@ -20,7 +20,7 @@ void main() {
testWidgets('insert/edit/open link', (tester) async { testWidgets('insert/edit/open link', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();

View File

@ -19,7 +19,7 @@ void main() {
group('outline block test', () { group('outline block test', () {
testWidgets('insert an outline block', (tester) async { testWidgets('insert an outline block', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
name: 'outline_test', name: 'outline_test',
@ -35,7 +35,7 @@ void main() {
testWidgets('insert an outline block and check if headings are visible', testWidgets('insert an outline block and check if headings are visible',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
name: 'outline_test', name: 'outline_test',
@ -91,7 +91,7 @@ void main() {
testWidgets("control the depth of outline block", (tester) async { testWidgets("control the depth of outline block", (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
name: 'outline_test', name: 'outline_test',

View File

@ -36,7 +36,7 @@ void main() {
testWidgets('convert > to toggle list, and click the icon to close it', testWidgets('convert > to toggle list, and click the icon to close it',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
@ -80,7 +80,7 @@ void main() {
(tester) async { (tester) async {
// if the toggle list is closed, press enter key will insert a new toggle list after it // if the toggle list is closed, press enter key will insert a new toggle list after it
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
@ -117,7 +117,7 @@ void main() {
testWidgets('press enter key when the toggle list is open', (tester) async { testWidgets('press enter key when the toggle list is open', (tester) async {
// if the toggle list is open, press enter key will insert a new paragraph inside it // if the toggle list is open, press enter key will insert a new paragraph inside it
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
@ -152,7 +152,7 @@ void main() {
testWidgets('clear the format if toggle list if empty', (tester) async { testWidgets('clear the format if toggle list if empty', (tester) async {
// if the toggle list is open, press enter key will insert a new paragraph inside it // if the toggle list is open, press enter key will insert a new paragraph inside it
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
@ -181,7 +181,7 @@ void main() {
(tester) async { (tester) async {
// if the toggle list is open, press enter key will insert a new paragraph inside it // if the toggle list is open, press enter key will insert a new paragraph inside it
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document // create a new document
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();

View File

@ -13,7 +13,7 @@ void main() {
group('edit document', () { group('edit document', () {
testWidgets('redo & undo', (tester) async { testWidgets('redo & undo', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document called Sample // create a new document called Sample
const pageName = 'Sample'; const pageName = 'Sample';
@ -67,7 +67,7 @@ void main() {
testWidgets('write a readme document', (tester) async { testWidgets('write a readme document', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new document called Sample // create a new document called Sample
const pageName = 'Sample'; const pageName = 'Sample';

View File

@ -13,7 +13,7 @@ void main() {
group('Grid Calculations', () { group('Grid Calculations', () {
testWidgets('add calculation and update cell', (tester) async { testWidgets('add calculation and update cell', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
@ -47,7 +47,7 @@ void main() {
testWidgets('add calculations and remove row', (tester) async { testWidgets('add calculations and remove row', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid); await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);

View File

@ -27,7 +27,7 @@ void main() {
const time = "23:59"; const time = "23:59";
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final dateTimeSettings = final dateTimeSettings =
await UserSettingsBackendService().getDateTimeSettings(); await UserSettingsBackendService().getDateTimeSettings();
@ -76,7 +76,7 @@ void main() {
testWidgets('Add reminder for tomorrow, and navigate to it', testWidgets('Add reminder for tomorrow, and navigate to it',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.editor.tapLineOfEditorAt(0); await tester.editor.tapLineOfEditorAt(0);
await tester.editor.getCurrentEditorState().insertNewLine(); await tester.editor.getCurrentEditorState().insertNewLine();

View File

@ -11,7 +11,7 @@ void main() {
group('board add row test', () { group('board add row test', () {
testWidgets('Add card from header', (tester) async { testWidgets('Add card from header', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.openSettings(); await tester.openSettings();
await tester.openSettingsPage(SettingsPage.notifications); await tester.openSettingsPage(SettingsPage.notifications);

View File

@ -14,7 +14,7 @@ void main() {
testWidgets('select language, language changed', (tester) async { testWidgets('select language, language changed', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings(); await tester.openSettings();

View File

@ -15,7 +15,7 @@ void main() {
group('Rename current view item', () { group('Rename current view item', () {
testWidgets('by F2 shortcut', (tester) async { testWidgets('by F2 shortcut', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await FlowyTestKeyboard.simulateKeyDownEvent( await FlowyTestKeyboard.simulateKeyDownEvent(
[LogicalKeyboardKey.f2], [LogicalKeyboardKey.f2],

View File

@ -27,7 +27,7 @@ void main() {
testWidgets('first time the personal folder is expanded', (tester) async { testWidgets('first time the personal folder is expanded', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// first time is expanded // first time is expanded
expect(isExpanded(type: FolderCategoryType.private), true); expect(isExpanded(type: FolderCategoryType.private), true);

View File

@ -18,7 +18,7 @@ void main() {
'Toggle favorites for views creates / removes the favorite header along with favorite views', 'Toggle favorites for views creates / removes the favorite header along with favorite views',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// no favorite folder // no favorite folder
expect(find.byType(FavoriteFolder), findsNothing); expect(find.byType(FavoriteFolder), findsNothing);
@ -74,7 +74,7 @@ void main() {
'renaming a favorite view updates name under favorite header', 'renaming a favorite view updates name under favorite header',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
const name = 'test'; const name = 'test';
await tester.favoriteViewByName(gettingStarted); await tester.favoriteViewByName(gettingStarted);
@ -100,7 +100,7 @@ void main() {
'deleting first level favorite view removes its instance from favorite header, deleting root level views leads to removal of all favorites that are its children', 'deleting first level favorite view removes its instance from favorite header, deleting root level views leads to removal of all favorites that are its children',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final names = [1, 2].map((e) => 'document_$e').toList(); final names = [1, 2].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
@ -157,7 +157,7 @@ void main() {
'view selection is synced between favorites and personal folder', 'view selection is synced between favorites and personal folder',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted); await tester.favoriteViewByName(gettingStarted);
@ -177,7 +177,7 @@ void main() {
'context menu opens up for favorites', 'context menu opens up for favorites',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(); await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted); await tester.favoriteViewByName(gettingStarted);

View File

@ -14,7 +14,7 @@ void main() {
group('Icon', () { group('Icon', () {
testWidgets('Update page icon in sidebar', (tester) async { testWidgets('Update page icon in sidebar', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create document, board, grid and calendar views // create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) { for (final value in ViewLayoutPB.values) {
@ -42,7 +42,7 @@ void main() {
testWidgets('Update page icon in title bar', (tester) async { testWidgets('Update page icon in title bar', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create document, board, grid and calendar views // create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) { for (final value in ViewLayoutPB.values) {

View File

@ -20,7 +20,7 @@ void main() {
group('sidebar test', () { group('sidebar test', () {
testWidgets('create a new page', (tester) async { testWidgets('create a new page', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// create a new page // create a new page
await tester.tapNewPageButton(); await tester.tapNewPageButton();
@ -36,7 +36,7 @@ void main() {
testWidgets('create a new document, grid, board and calendar', testWidgets('create a new document, grid, board and calendar',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
for (final layout in ViewLayoutPB.values) { for (final layout in ViewLayoutPB.values) {
// create a new page // create a new page
@ -74,7 +74,7 @@ void main() {
testWidgets('create some nested pages, and move them', (tester) async { testWidgets('create some nested pages, and move them', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final names = [1, 2, 3, 4].map((e) => 'document_$e').toList(); final names = [1, 2, 3, 4].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
@ -140,7 +140,7 @@ void main() {
testWidgets('unable to move a document into a database', (tester) async { testWidgets('unable to move a document into a database', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
const document = 'document'; const document = 'document';
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(
@ -183,7 +183,7 @@ void main() {
testWidgets('unable to create a new database inside the existing one', testWidgets('unable to create a new database inside the existing one',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
const grid = 'grid'; const grid = 'grid';
await tester.createNewPageWithNameUnderParent( await tester.createNewPageWithNameUnderParent(

View File

@ -15,7 +15,7 @@ void main() {
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings(); await tester.openSettings();
@ -47,7 +47,7 @@ void main() {
testWidgets('reset the font family', (tester) async { testWidgets('reset the font family', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings(); await tester.openSettings();

View File

@ -17,7 +17,7 @@ void main() {
testWidgets('cmd/ctrl+alt+e shortcut opens the emoji picker', testWidgets('cmd/ctrl+alt+e shortcut opens the emoji picker',
(tester) async { (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
final Finder editor = find.byType(AppFlowyEditor); final Finder editor = find.byType(AppFlowyEditor);
await tester.tap(editor); await tester.tap(editor);

View File

@ -10,7 +10,7 @@ void main() {
group('Empty', () { group('Empty', () {
testWidgets('toggle theme mode', (tester) async { testWidgets('toggle theme mode', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
}); });
}); });
} }

View File

@ -19,7 +19,7 @@ void main() {
testWidgets('toggle theme mode', (tester) async { testWidgets('toggle theme mode', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings(); await tester.openSettings();
@ -71,7 +71,7 @@ void main() {
testWidgets('show or hide home menu', (tester) async { testWidgets('show or hide home menu', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle(); await tester.pumpAndSettle();

View File

@ -15,7 +15,7 @@ void main() {
group('import files', () { group('import files', () {
testWidgets('import multiple markdown files', (tester) async { testWidgets('import multiple markdown files', (tester) async {
final context = await tester.initializeAppFlowy(); final context = await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// expect to see a getting started page // expect to see a getting started page
tester.expectToSeePageName(gettingStarted); tester.expectToSeePageName(gettingStarted);
@ -48,7 +48,7 @@ void main() {
testWidgets('import markdown file with table', (tester) async { testWidgets('import markdown file with table', (tester) async {
final context = await tester.initializeAppFlowy(); final context = await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// expect to see a getting started page // expect to see a getting started page
tester.expectToSeePageName(gettingStarted); tester.expectToSeePageName(gettingStarted);
@ -77,12 +77,18 @@ void main() {
await tester.openPage('markdown_with_table'); await tester.openPage('markdown_with_table');
final importedPageEditorState = tester.editor.getCurrentEditorState(); final importedPageEditorState = tester.editor.getCurrentEditorState();
expect(importedPageEditorState.getNodeAtPath([0])!.type, expect(
HeadingBlockKeys.type,); importedPageEditorState.getNodeAtPath([0])!.type,
expect(importedPageEditorState.getNodeAtPath([2])!.type, HeadingBlockKeys.type,
HeadingBlockKeys.type,); );
expect(importedPageEditorState.getNodeAtPath([4])!.type, expect(
TableBlockKeys.type,); importedPageEditorState.getNodeAtPath([2])!.type,
HeadingBlockKeys.type,
);
expect(
importedPageEditorState.getNodeAtPath([4])!.type,
TableBlockKeys.type,
);
}); });
}); });
} }

View File

@ -14,7 +14,7 @@ void main() {
group('share markdown in document page', () { group('share markdown in document page', () {
testWidgets('click the share button in document page', (tester) async { testWidgets('click the share button in document page', (tester) async {
final context = await tester.initializeAppFlowy(); final context = await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// mock the file picker // mock the file picker
final path = await mockSaveFilePath( final path = await mockSaveFilePath(
@ -38,7 +38,7 @@ void main() {
'share the markdown after renaming the document name', 'share the markdown after renaming the document name',
(tester) async { (tester) async {
final context = await tester.initializeAppFlowy(); final context = await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// expect to see a getting started page // expect to see a getting started page
tester.expectToSeePageName(gettingStarted); tester.expectToSeePageName(gettingStarted);
@ -104,12 +104,12 @@ fn main() {
> Click `?` at the bottom right for help and support. > Click `?` at the bottom right for help and support.
> 🥰 > 🥰
> >
> Like AppFlowy? Follow us: > Like AppFlowy? Follow us:
> [GitHub](https://github.com/AppFlowy-IO/AppFlowy) > [GitHub](https://github.com/AppFlowy-IO/AppFlowy)
> [Twitter](https://twitter.com/appflowy): @appflowy > [Twitter](https://twitter.com/appflowy): @appflowy
> [Newsletter](https://blog-appflowy.ghost.io/) > [Newsletter](https://blog-appflowy.ghost.io/)
> >

View File

@ -94,7 +94,7 @@ void main() {
testWidgets('reset to default location', (tester) async { testWidgets('reset to default location', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
// home and readme document // home and readme document
await tester.expectToSeeHomePageWithGetStartedPage(); await tester.expectToSeeHomePageWithGetStartedPage();

View File

@ -22,7 +22,7 @@ void main() {
group('Tabs', () { group('Tabs', () {
testWidgets('Open AppFlowy and open/navigate/close tabs', (tester) async { testWidgets('Open AppFlowy and open/navigate/close tabs', (tester) async {
await tester.initializeAppFlowy(); await tester.initializeAppFlowy();
await tester.tapGoButton(); await tester.tapAnonymousSignInButton();
expect( expect(
find.descendant( find.descendant(

View File

@ -118,7 +118,7 @@ extension AppFlowyTestBase on WidgetTester {
Future<void> waitUntilSignInPageShow() async { Future<void> waitUntilSignInPageShow() async {
if (isAuthEnabled) { if (isAuthEnabled) {
final finder = find.byType(SignInAnonymousButton); final finder = find.byType(SignInAnonymousButtonV2);
await pumpUntilFound(finder, timeout: const Duration(seconds: 30)); await pumpUntilFound(finder, timeout: const Duration(seconds: 30));
expect(finder, findsOneWidget); expect(finder, findsOneWidget);
} else { } else {

View File

@ -36,14 +36,14 @@ import 'util.dart';
extension CommonOperations on WidgetTester { extension CommonOperations on WidgetTester {
/// Tap the GetStart button on the launch page. /// Tap the GetStart button on the launch page.
Future<void> tapGoButton() async { Future<void> tapAnonymousSignInButton() async {
// local version // local version
final goButton = find.byType(GoButton); final goButton = find.byType(GoButton);
if (goButton.evaluate().isNotEmpty) { if (goButton.evaluate().isNotEmpty) {
await tapButton(goButton); await tapButton(goButton);
} else { } else {
// cloud version // cloud version
final anonymousButton = find.byType(SignInAnonymousButton); final anonymousButton = find.byType(SignInAnonymousButtonV2);
await tapButton(anonymousButton); await tapButton(anonymousButton);
} }

View File

@ -98,7 +98,7 @@ import 'mock/mock_file_picker.dart';
extension AppFlowyDatabaseTest on WidgetTester { extension AppFlowyDatabaseTest on WidgetTester {
Future<void> openV020database() async { Future<void> openV020database() async {
final context = await initializeAppFlowy(); final context = await initializeAppFlowy();
await tapGoButton(); await tapAnonymousSignInButton();
// expect to see a readme page // expect to see a readme page
expectToSeePageName(gettingStarted); expectToSeePageName(gettingStarted);

View File

@ -194,7 +194,10 @@ class InitAppFlowyCloudTask extends LaunchTask {
} }
class DeepLinkResult { class DeepLinkResult {
DeepLinkResult({required this.state, this.result}); DeepLinkResult({
required this.state,
this.result,
});
final DeepLinkState state; final DeepLinkState state;
final FlowyResult<UserProfilePB, FlowyError>? result; final FlowyResult<UserProfilePB, FlowyError>? result;

View File

@ -100,7 +100,10 @@ class AppFlowyCloudAuthService implements AuthService {
required String email, required String email,
Map<String, String> params = const {}, Map<String, String> params = const {},
}) async { }) async {
throw UnimplementedError(); return _backendAuthService.signInWithMagicLink(
email: email,
params: params,
);
} }
@override @override

View File

@ -72,7 +72,7 @@ abstract class AuthService {
/// - `params`: Additional parameters for authentication with magic link (optional). /// - `params`: Additional parameters for authentication with magic link (optional).
/// ///
/// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError]. /// Returns [UserProfilePB] if the user is authenticated, otherwise returns [FlowyError].
Future<FlowyResult<UserProfilePB, FlowyError>> signInWithMagicLink({ Future<FlowyResult<void, FlowyError>> signInWithMagicLink({
required String email, required String email,
Map<String, String> params, Map<String, String> params,
}); });

View File

@ -104,10 +104,7 @@ class BackendAuthService implements AuthService {
required String email, required String email,
Map<String, String> params = const {}, Map<String, String> params = const {},
}) async { }) async {
return FlowyResult.failure( // No need to pass the redirect URL.
FlowyError.create() return UserBackendService.signInWithMagicLink(email, '');
..code = ErrorCode.Internal
..msg = "Unsupported sign up action",
);
} }
} }

View File

@ -7,6 +7,7 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB; show UserProfilePB;
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@ -23,11 +24,58 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
}); });
} }
_dispatch(); on<SignInEvent>(
(event, emit) async {
await event.when(
signedInWithUserEmailAndPassword: () async => _onSignIn(emit),
signedInWithOAuth: (platform) async => _onSignInWithOAuth(
emit,
platform,
),
signedInAsGuest: () async => _onSignInAsGuest(emit),
signedWithMagicLink: (email) async => _onSignInWithMagicLink(
emit,
email,
),
deepLinkStateChange: (result) => _onDeepLinkStateChange(
emit,
result,
),
cancel: () {
emit(
state.copyWith(
isSubmitting: false,
emailError: null,
passwordError: null,
successOrFail: null,
),
);
},
emailChanged: (email) async {
emit(
state.copyWith(
email: email,
emailError: null,
successOrFail: null,
),
);
},
passwordChanged: (password) async {
emit(
state.copyWith(
password: password,
passwordError: null,
successOrFail: null,
),
);
},
);
},
);
} }
final AuthService authService; final AuthService authService;
void Function()? deepLinkStateListener; VoidCallback? deepLinkStateListener;
@override @override
Future<void> close() { Future<void> close() {
@ -40,87 +88,39 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
return super.close(); return super.close();
} }
void _dispatch() { Future<void> _onDeepLinkStateChange(
on<SignInEvent>( Emitter<SignInState> emit,
(event, emit) async { DeepLinkResult result,
await event.map( ) async {
signedInWithUserEmailAndPassword: (e) async { final deepLinkState = result.state;
await _performActionOnSignIn(
state,
emit,
);
},
signedInWithOAuth: (value) async =>
_performActionOnSignInWithOAuth(state, emit, value.platform),
signedInAsGuest: (value) async =>
_performActionOnSignInAsGuest(state, emit),
emailChanged: (EmailChanged value) async {
emit(
state.copyWith(
email: value.email,
emailError: null,
successOrFail: null,
),
);
},
passwordChanged: (PasswordChanged value) async {
emit(
state.copyWith(
password: value.password,
passwordError: null,
successOrFail: null,
),
);
},
signedWithMagicLink: (SignedWithMagicLink value) async {
await _performActionOnSignInWithMagicLink(state, emit, value.email);
},
deepLinkStateChange: (_DeepLinkStateChange value) {
final deepLinkState = value.result.state;
switch (deepLinkState) { switch (deepLinkState) {
case DeepLinkState.none: case DeepLinkState.none:
break; break;
case DeepLinkState.loading: case DeepLinkState.loading:
emit( emit(
state.copyWith( state.copyWith(
isSubmitting: true, isSubmitting: true,
emailError: null, emailError: null,
passwordError: null, passwordError: null,
successOrFail: null, successOrFail: null,
), ),
);
case DeepLinkState.finish:
if (value.result.result != null) {
emit(
value.result.result!.fold(
(userProfile) => state.copyWith(
isSubmitting: false,
successOrFail: FlowyResult.success(userProfile),
),
(error) => stateFromCode(error),
),
);
}
}
},
cancel: (value) {
emit(
state.copyWith(
isSubmitting: false,
emailError: null,
passwordError: null,
successOrFail: null,
),
);
},
); );
}, case DeepLinkState.finish:
); final newState = result.result?.fold(
(s) => state.copyWith(
isSubmitting: false,
successOrFail: FlowyResult.success(s),
),
(f) => _stateFromCode(f),
);
if (newState != null) {
emit(newState);
}
}
} }
Future<void> _performActionOnSignIn( Future<void> _onSignIn(
SignInState state,
Emitter<SignInState> emit, Emitter<SignInState> emit,
) async { ) async {
final result = await authService.signInWithEmailPassword( final result = await authService.signInWithEmailPassword(
@ -133,13 +133,12 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
isSubmitting: false, isSubmitting: false,
successOrFail: FlowyResult.success(userProfile), successOrFail: FlowyResult.success(userProfile),
), ),
(error) => stateFromCode(error), (error) => _stateFromCode(error),
), ),
); );
} }
Future<void> _performActionOnSignInWithOAuth( Future<void> _onSignInWithOAuth(
SignInState state,
Emitter<SignInState> emit, Emitter<SignInState> emit,
String platform, String platform,
) async { ) async {
@ -161,13 +160,12 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
isSubmitting: false, isSubmitting: false,
successOrFail: FlowyResult.success(userProfile), successOrFail: FlowyResult.success(userProfile),
), ),
(error) => stateFromCode(error), (error) => _stateFromCode(error),
), ),
); );
} }
Future<void> _performActionOnSignInWithMagicLink( Future<void> _onSignInWithMagicLink(
SignInState state,
Emitter<SignInState> emit, Emitter<SignInState> emit,
String email, String email,
) async { ) async {
@ -187,16 +185,14 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
emit( emit(
result.fold( result.fold(
(userProfile) => state.copyWith( (userProfile) => state.copyWith(
isSubmitting: false, isSubmitting: true,
successOrFail: FlowyResult.success(userProfile),
), ),
(error) => stateFromCode(error), (error) => _stateFromCode(error),
), ),
); );
} }
Future<void> _performActionOnSignInAsGuest( Future<void> _onSignInAsGuest(
SignInState state,
Emitter<SignInState> emit, Emitter<SignInState> emit,
) async { ) async {
emit( emit(
@ -215,12 +211,12 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
isSubmitting: false, isSubmitting: false,
successOrFail: FlowyResult.success(userProfile), successOrFail: FlowyResult.success(userProfile),
), ),
(error) => stateFromCode(error), (error) => _stateFromCode(error),
), ),
); );
} }
SignInState stateFromCode(FlowyError error) { SignInState _stateFromCode(FlowyError error) {
switch (error.code) { switch (error.code) {
case ErrorCode.EmailFormatInvalid: case ErrorCode.EmailFormatInvalid:
return state.copyWith( return state.copyWith(
@ -255,7 +251,7 @@ class SignInEvent with _$SignInEvent {
const factory SignInEvent.emailChanged(String email) = EmailChanged; const factory SignInEvent.emailChanged(String email) = EmailChanged;
const factory SignInEvent.passwordChanged(String password) = PasswordChanged; const factory SignInEvent.passwordChanged(String password) = PasswordChanged;
const factory SignInEvent.deepLinkStateChange(DeepLinkResult result) = const factory SignInEvent.deepLinkStateChange(DeepLinkResult result) =
_DeepLinkStateChange; DeepLinkStateChange;
const factory SignInEvent.cancel() = _Cancel; const factory SignInEvent.cancel() = _Cancel;
} }

View File

@ -63,6 +63,14 @@ class UserBackendService {
throw UnimplementedError(); throw UnimplementedError();
} }
static Future<FlowyResult<UserProfilePB, FlowyError>> signInWithMagicLink(
String email,
String redirectTo,
) async {
final payload = MagicLinkSignInPB(email: email, redirectTo: redirectTo);
return UserEventMagicLinkSignIn(payload).send();
}
static Future<FlowyResult<void, FlowyError>> signOut() { static Future<FlowyResult<void, FlowyError>> signOut() {
return UserEventSignOut().send(); return UserEventSignOut().send();
} }

View File

@ -1,6 +1,7 @@
import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/core/frameless_window.dart';
import 'package:appflowy/env/cloud_env.dart'; import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/magic_link_sign_in_buttons.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart'; import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/user/presentation/widgets/widgets.dart'; import 'package:appflowy/user/presentation/widgets/widgets.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -28,22 +29,9 @@ class DesktopSignInScreen extends StatelessWidget {
logoSize: const Size(60, 60), logoSize: const Size(60, 60),
), ),
const VSpace(30), const VSpace(30),
// Email and password. don't support yet.
/*
...[
const EmailTextField(),
const VSpace(5),
const PasswordTextField(),
const VSpace(20),
const LoginButton(),
const VSpace(10),
const VSpace(10),
SignUpPrompt(router: router),
],
*/
const SignInAnonymousButton(), // const SignInAnonymousButton(),
const SignInWithMagicLinkButtons(),
// third-party sign in. // third-party sign in.
const VSpace(20), const VSpace(20),
@ -54,6 +42,10 @@ class DesktopSignInScreen extends StatelessWidget {
const ThirdPartySignInButtons(), const ThirdPartySignInButtons(),
], ],
const VSpace(20), const VSpace(20),
// anonymous sign in
const SignInAnonymousButtonV2(),
// loading status // loading status
const VSpace(indicatorMinHeight), const VSpace(indicatorMinHeight),
isLoading isLoading
@ -61,18 +53,6 @@ class DesktopSignInScreen extends StatelessWidget {
minHeight: indicatorMinHeight, minHeight: indicatorMinHeight,
) )
: const VSpace(indicatorMinHeight), : const VSpace(indicatorMinHeight),
// add the same space when there's no loading status.
// ConstrainedBox(
// constraints: const BoxConstraints(maxHeight: 140),
// child: HistoricalUserList(
// didOpenUser: () async {
// await FlowyRunner.run(
// FlowyApp(),
// integrationEnv(),
// );
// },
// ),
// ),
const VSpace(20), const VSpace(20),
], ],
), ),
@ -106,136 +86,3 @@ class _OrDivider extends StatelessWidget {
); );
} }
} }
// The following code is migrated from previous signInScreen.dart(for desktop)
// We may need this later when sign up&in feature is ready
// class SignUpPrompt extends StatelessWidget {
// const SignUpPrompt({
// super.key,
// required this.router,
// }) ;
// final AuthRouter router;
// @override
// Widget build(BuildContext context) {
// return Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// FlowyText.medium(
// LocaleKeys.signIn_dontHaveAnAccount.tr(),
// color: Theme.of(context).hintColor,
// ),
// TextButton(
// style: TextButton.styleFrom(
// textStyle: Theme.of(context).textTheme.bodyMedium,
// ),
// onPressed: () => router.pushSignUpScreen(context),
// child: Text(
// LocaleKeys.signUp_buttonText.tr(),
// style: TextStyle(color: Theme.of(context).colorScheme.primary),
// ),
// ),
// ForgetPasswordButton(router: router),
// ],
// );
// }
// }
// class LoginButton extends StatelessWidget {
// const LoginButton({
// super.key
// }) ;
// @override
// Widget build(BuildContext context) {
// return RoundedTextButton(
// title: LocaleKeys.signIn_loginButtonText.tr(),
// height: 48,
// borderRadius: Corners.s10Border,
// onPressed: () => context
// .read<SignInBloc>()
// .add(const SignInEvent.signedInWithUserEmailAndPassword()),
// );
// }
// }
// class ForgetPasswordButton extends StatelessWidget {
// const ForgetPasswordButton({
// super.key
// required this.router,
// }) ;
// final AuthRouter router;
// @override
// Widget build(BuildContext context) {
// return TextButton(
// style: TextButton.styleFrom(
// textStyle: Theme.of(context).textTheme.bodyMedium,
// ),
// onPressed: () {
// throw UnimplementedError();
// },
// child: Text(
// LocaleKeys.signIn_forgotPassword.tr(),
// style: TextStyle(color: Theme.of(context).colorScheme.primary),
// ),
// );
// }
// }
// class PasswordTextField extends StatelessWidget {
// const PasswordTextField({
// super.key
// }) ;
// @override
// Widget build(BuildContext context) {
// return BlocBuilder<SignInBloc, SignInState>(
// buildWhen: (previous, current) =>
// previous.passwordError != current.passwordError,
// builder: (context, state) {
// return RoundedInputField(
// obscureText: true,
// obscureIcon: const FlowySvg(FlowySvgs.hide_m),
// obscureHideIcon: const FlowySvg(FlowySvgs.show_m),
// hintText: LocaleKeys.signIn_passwordHint.tr(),
// errorText: context
// .read<SignInBloc>()
// .state
// .passwordError
// .fold(() => "", (error) => error),
// onChanged: (value) => context
// .read<SignInBloc>()
// .add(SignInEvent.passwordChanged(value)),
// );
// },
// );
// }
// }
// class EmailTextField extends StatelessWidget {
// const EmailTextField({
// super.key
// }) ;
// @override
// Widget build(BuildContext context) {
// return BlocBuilder<SignInBloc, SignInState>(
// buildWhen: (previous, current) =>
// previous.emailError != current.emailError,
// builder: (context, state) {
// return RoundedInputField(
// hintText: LocaleKeys.signIn_emailHint.tr(),
// errorText: context
// .read<SignInBloc>()
// .state
// .emailError
// .fold(() => "", (error) => error),
// onChanged: (value) =>
// context.read<SignInBloc>().add(SignInEvent.emailChanged(value)),
// );
// },
// );
// }
// }

View File

@ -2,6 +2,7 @@ import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/setting/launch_settings_page.dart'; import 'package:appflowy/mobile/presentation/setting/launch_settings_page.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/magic_link_sign_in_buttons.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart'; import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -27,15 +28,14 @@ class MobileSignInScreen extends StatelessWidget {
const VSpace(spacing * 2), const VSpace(spacing * 2),
_buildWelcomeText(), _buildWelcomeText(),
_buildAppNameText(colorScheme), _buildAppNameText(colorScheme),
const VSpace(spacing * 2),
const SignInWithMagicLinkButtons(),
const VSpace(spacing), const VSpace(spacing),
const Spacer(flex: 2), if (isAuthEnabled) _buildThirdPartySignInButtons(colorScheme),
const SignInAnonymousButton(),
const VSpace(spacing), const VSpace(spacing),
if (isAuthEnabled) ...[ const SignInAnonymousButtonV2(),
_buildThirdPartySignInButtons(colorScheme), const VSpace(spacing),
const VSpace(spacing), _buildSettingsButton(context),
_buildSettingsButton(context),
],
if (!isAuthEnabled) const Spacer(flex: 2), if (!isAuthEnabled) const Spacer(flex: 2),
], ],
), ),

View File

@ -0,0 +1,109 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/application/sign_in_bloc.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:string_validator/string_validator.dart';
class SignInWithMagicLinkButtons extends StatefulWidget {
const SignInWithMagicLinkButtons({
super.key,
});
@override
State<SignInWithMagicLinkButtons> createState() =>
_SignInWithMagicLinkButtonsState();
}
class _SignInWithMagicLinkButtonsState
extends State<SignInWithMagicLinkButtons> {
final controller = TextEditingController();
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 48.0,
child: FlowyTextField(
controller: controller,
hintText: LocaleKeys.signIn_pleaseInputYourEmail.tr(),
onSubmitted: (_) => _sendMagicLink(context, controller.text),
),
),
const VSpace(12),
_ConfirmButton(
onTap: () => _sendMagicLink(context, controller.text),
),
],
);
}
void _sendMagicLink(BuildContext context, String email) {
if (!isEmail(email)) {
showSnackBarMessage(
context,
LocaleKeys.signIn_invalidEmail.tr(),
duration: const Duration(seconds: 8),
);
return;
}
context.read<SignInBloc>().add(SignInEvent.signedWithMagicLink(email));
showSnackBarMessage(
context,
LocaleKeys.signIn_magicLinkSent.tr(),
duration: const Duration(seconds: 1000),
);
}
}
class _ConfirmButton extends StatelessWidget {
const _ConfirmButton({
required this.onTap,
});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
if (PlatformExtension.isMobile) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 56),
),
onPressed: onTap,
child: FlowyText(
LocaleKeys.signIn_logInWithMagicLink.tr(),
fontSize: 14,
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.w500,
),
);
} else {
return SizedBox(
height: 48,
child: FlowyButton(
isSelected: true,
onTap: onTap,
hoverColor: Theme.of(context).colorScheme.primary,
text: FlowyText.medium(
LocaleKeys.signIn_logInWithMagicLink.tr(),
textAlign: TextAlign.center,
),
radius: Corners.s6Border,
),
);
}
}
}

View File

@ -9,8 +9,8 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
/// Used in DesktopSignInScreen and MobileSignInScreen
class SignInAnonymousButton extends StatelessWidget { class SignInAnonymousButton extends StatelessWidget {
/// Used in DesktopSignInScreen and MobileSignInScreen
const SignInAnonymousButton({ const SignInAnonymousButton({
super.key, super.key,
}); });
@ -85,3 +85,59 @@ class SignInAnonymousButton extends StatelessWidget {
); );
} }
} }
class SignInAnonymousButtonV2 extends StatelessWidget {
const SignInAnonymousButtonV2({
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<SignInBloc, SignInState>(
builder: (context, signInState) {
return BlocProvider(
create: (context) => AnonUserBloc()
..add(
const AnonUserEvent.initial(),
),
child: BlocListener<AnonUserBloc, AnonUserState>(
listener: (context, state) async {
if (state.openedAnonUser != null) {
await runAppFlowy();
}
},
child: BlocBuilder<AnonUserBloc, AnonUserState>(
builder: (context, state) {
final text = state.anonUsers.isEmpty
? LocaleKeys.signIn_loginStartWithAnonymous.tr()
: LocaleKeys.signIn_continueAnonymousUser.tr();
final onTap = state.anonUsers.isEmpty
? () {
context
.read<SignInBloc>()
.add(const SignInEvent.signedInAsGuest());
}
: () {
final bloc = context.read<AnonUserBloc>();
final user = bloc.state.anonUsers.first;
bloc.add(AnonUserEvent.openAnonUser(user));
};
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: onTap,
child: FlowyText(
text,
color: Colors.blue,
fontSize: 12,
),
),
);
},
),
),
);
},
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
@ -53,10 +54,11 @@ void showSnackBarMessage(
BuildContext context, BuildContext context,
String message, { String message, {
bool showCancel = false, bool showCancel = false,
Duration duration = const Duration(seconds: 4),
}) { }) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
backgroundColor: Theme.of(context).colorScheme.onSecondary, backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
action: !showCancel action: !showCancel
? null ? null
: SnackBarAction( : SnackBarAction(
@ -68,8 +70,8 @@ void showSnackBarMessage(
), ),
content: FlowyText( content: FlowyText(
message, message,
color: Colors.white,
maxLines: 2, maxLines: 2,
fontSize: PlatformExtension.isDesktop ? 14 : 12,
), ),
), ),
); );

View File

@ -11,6 +11,8 @@ const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
int32_t set_stream_port(int64_t port); int32_t set_stream_port(int64_t port);
int32_t set_log_stream_port(int64_t port);
void link_me_please(void); void link_me_please(void);
void rust_log(int64_t level, const char *data); void rust_log(int64_t level, const char *data);

View File

@ -1,10 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flowy_infra/size.dart';
class FlowyTextField extends StatefulWidget { class FlowyTextField extends StatefulWidget {
final String? hintText; final String? hintText;
final String? text; final String? text;

View File

@ -156,7 +156,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -712,7 +712,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -757,7 +757,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -996,7 +996,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1021,7 +1021,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1258,7 +1258,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa 1.0.6", "itoa 1.0.6",
"phf 0.8.0", "phf 0.11.2",
"smallvec", "smallvec",
] ]
@ -1369,7 +1369,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2679,7 +2679,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2696,7 +2696,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -3118,7 +3118,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -5518,7 +5518,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",

View File

@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -215,7 +215,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -541,7 +541,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -586,7 +586,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -764,7 +764,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -789,7 +789,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -955,7 +955,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa", "itoa",
"phf 0.8.0", "phf 0.11.2",
"smallvec", "smallvec",
] ]
@ -1000,7 +1000,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -1762,7 +1762,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -1779,7 +1779,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2080,7 +2080,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -2763,7 +2763,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [ dependencies = [
"phf_macros", "phf_macros 0.8.0",
"phf_shared 0.8.0", "phf_shared 0.8.0",
"proc-macro-hack", "proc-macro-hack",
] ]
@ -2783,6 +2783,7 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2", "phf_shared 0.11.2",
] ]
@ -2850,6 +2851,19 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.8.0" version = "0.8.0"
@ -3705,7 +3719,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",

View File

@ -55,7 +55,7 @@ codegen-units = 1
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -147,7 +147,7 @@ checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -687,7 +687,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -732,7 +732,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -980,7 +980,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1005,7 +1005,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1246,7 +1246,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa 1.0.10", "itoa 1.0.10",
"phf 0.11.2", "phf 0.8.0",
"smallvec", "smallvec",
] ]
@ -1357,7 +1357,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2749,7 +2749,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2766,7 +2766,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -3193,7 +3193,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -5609,7 +5609,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",

View File

@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -50,7 +50,11 @@
"LogInWithGithub": "Log in with Github", "LogInWithGithub": "Log in with Github",
"LogInWithDiscord": "Log in with Discord", "LogInWithDiscord": "Log in with Discord",
"signInWith": "Sign in with:", "signInWith": "Sign in with:",
"signInWithEmail": "Sign in with Email" "signInWithEmail": "Sign in with Email",
"logInWithMagicLink": "Log in with Magic Link",
"pleaseInputYourEmail": "Please enter your email address",
"magicLinkSent": "Magic link sent to your email, please check your inbox",
"invalidEmail": "Please enter a valid email address"
}, },
"workspace": { "workspace": {
"chooseWorkspace": "Choose your workspace", "chooseWorkspace": "Choose your workspace",

View File

@ -157,7 +157,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -669,7 +669,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -714,7 +714,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -922,7 +922,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -947,7 +947,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1292,7 +1292,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2481,7 +2481,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2498,7 +2498,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2859,7 +2859,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -4873,7 +4873,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e#dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",

View File

@ -111,7 +111,7 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1
# Run the script.add_workspace_members: # Run the script.add_workspace_members:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" } client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "dd9cc8d4c78c6d9bfeb9bd7d413222f643c7969e" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #

View File

@ -122,6 +122,23 @@ where
}) })
} }
fn sign_in_with_magic_link(
&self,
email: &str,
redirect_to: &str,
) -> FutureResult<(), FlowyError> {
let email = email.to_owned();
let redirect_to = redirect_to.to_owned();
let try_get_client = self.server.try_get_client();
FutureResult::new(async move {
let client = try_get_client?;
client
.sign_in_with_magic_link(&email, Some(redirect_to))
.await?;
Ok(())
})
}
fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, FlowyError> { fn generate_oauth_url_with_provider(&self, provider: &str) -> FutureResult<String, FlowyError> {
let provider = AuthProvider::from(provider); let provider = AuthProvider::from(provider);
let try_get_client = self.server.try_get_client(); let try_get_client = self.server.try_get_client();

View File

@ -107,6 +107,16 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
}) })
} }
fn sign_in_with_magic_link(
&self,
_email: &str,
_redirect_to: &str,
) -> FutureResult<(), FlowyError> {
FutureResult::new(async {
Err(FlowyError::local_version_not_support().with_context("Not support"))
})
}
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> { fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> {
FutureResult::new(async { FutureResult::new(async {
Err(FlowyError::internal().with_context("Can't oauth url when using offline mode")) Err(FlowyError::internal().with_context("Can't oauth url when using offline mode"))

View File

@ -187,6 +187,18 @@ where
}) })
} }
fn sign_in_with_magic_link(
&self,
_email: &str,
_redirect_to: &str,
) -> FutureResult<(), FlowyError> {
FutureResult::new(async {
Err(
FlowyError::not_support().with_context("Can't sign in with magic link when using supabase"),
)
})
}
fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> { fn generate_oauth_url_with_provider(&self, _provider: &str) -> FutureResult<String, FlowyError> {
FutureResult::new(async { FutureResult::new(async {
Err(FlowyError::internal().with_context("Can't generate oauth url when using supabase")) Err(FlowyError::internal().with_context("Can't generate oauth url when using supabase"))

View File

@ -142,6 +142,9 @@ pub trait UserCloudService: Send + Sync + 'static {
password: &str, password: &str,
) -> FutureResult<UserProfile, FlowyError>; ) -> FutureResult<UserProfile, FlowyError>;
fn sign_in_with_magic_link(&self, email: &str, redirect_to: &str)
-> FutureResult<(), FlowyError>;
/// When the user opens the OAuth URL, it redirects to the corresponding provider's OAuth web page. /// When the user opens the OAuth URL, it redirects to the corresponding provider's OAuth web page.
/// After the user is authenticated, the browser will open a deep link to the AppFlowy app (iOS, macOS, etc.), /// After the user is authenticated, the browser will open a deep link to the AppFlowy app (iOS, macOS, etc.),
/// which will call [Client::sign_in_with_url]generate_sign_in_url_with_email to sign in. /// which will call [Client::sign_in_with_url]generate_sign_in_url_with_email to sign in.

View File

@ -77,6 +77,15 @@ impl TryInto<SignUpParams> for SignUpPayloadPB {
} }
} }
#[derive(ProtoBuf, Default)]
pub struct MagicLinkSignInPB {
#[pb(index = 1)]
pub email: String,
#[pb(index = 2)]
pub redirect_to: String,
}
#[derive(ProtoBuf, Default)] #[derive(ProtoBuf, Default)]
pub struct OauthSignInPB { pub struct OauthSignInPB {
/// Use this field to store the third party auth information. /// Use this field to store the third party auth information.

View File

@ -288,6 +288,19 @@ pub async fn get_user_setting(
data_result_ok(user_setting) data_result_ok(user_setting)
} }
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub async fn sign_in_with_magic_link_handler(
data: AFPluginData<MagicLinkSignInPB>,
manager: AFPluginState<Weak<UserManager>>,
) -> Result<(), FlowyError> {
let manager = upgrade_manager(manager)?;
let params = data.into_inner();
manager
.sign_in_with_magic_link(&params.email, &params.redirect_to)
.await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(data, manager), err)] #[tracing::instrument(level = "debug", skip(data, manager), err)]
pub async fn oauth_sign_in_handler( pub async fn oauth_sign_in_handler(
data: AFPluginData<OauthSignInPB>, data: AFPluginData<OauthSignInPB>,

View File

@ -23,6 +23,7 @@ pub fn init(user_manager: Weak<UserManager>) -> AFPlugin {
.state(user_manager) .state(user_manager)
.state(store_preferences) .state(store_preferences)
.event(UserEvent::SignInWithEmailPassword, sign_in_with_email_password_handler) .event(UserEvent::SignInWithEmailPassword, sign_in_with_email_password_handler)
.event(UserEvent::MagicLinkSignIn, sign_in_with_magic_link_handler)
.event(UserEvent::SignUp, sign_up) .event(UserEvent::SignUp, sign_up)
.event(UserEvent::InitUser, init_user_handler) .event(UserEvent::InitUser, init_user_handler)
.event(UserEvent::GetUserProfile, get_user_profile_handler) .event(UserEvent::GetUserProfile, get_user_profile_handler)
@ -226,6 +227,9 @@ pub enum UserEvent {
#[event(input = "AcceptWorkspaceInvitationPB")] #[event(input = "AcceptWorkspaceInvitationPB")]
AcceptWorkspaceInvitation = 49, AcceptWorkspaceInvitation = 49,
#[event(input = "MagicLinkSignInPB", output = "UserProfilePB")]
MagicLinkSignIn = 50,
} }
pub trait UserStatusCallback: Send + Sync + 'static { pub trait UserStatusCallback: Send + Sync + 'static {

View File

@ -672,6 +672,18 @@ impl UserManager {
Ok(url) Ok(url)
} }
pub(crate) async fn sign_in_with_magic_link(
&self,
email: &str,
redirect_to: &str,
) -> Result<(), FlowyError> {
let auth_service = self.cloud_services.get_user_service()?;
auth_service
.sign_in_with_magic_link(email, redirect_to)
.await
.map_err(|err| FlowyError::server_error().with_context(err))
}
pub(crate) async fn generate_oauth_url( pub(crate) async fn generate_oauth_url(
&self, &self,
oauth_provider: &str, oauth_provider: &str,