Compare commits
2 Commits
renovate/f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
ea64470a4b
|
|||
|
4819f6f534
|
@@ -1 +1 @@
|
|||||||
flutter 3.44.1-stable
|
flutter 3.44.0-stable
|
||||||
|
|||||||
36
lib/core/api/v1/projects.dart
Normal file
36
lib/core/api/v1/projects.dart
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:grpc/grpc_web.dart';
|
||||||
|
import 'package:softplayer_dart_proto/projects/v1/projects_v1.pbgrpc.dart';
|
||||||
|
import 'package:softplayer_web/core/grpc/grpc_client.dart';
|
||||||
|
|
||||||
|
final projectsGrpcProvider = Provider<ProjectsGrpcRepository>((ref) {
|
||||||
|
return ProjectsGrpcRepository(ref.watch(projectsServiceClientProvider));
|
||||||
|
});
|
||||||
|
|
||||||
|
class ProjectsGrpcRepository {
|
||||||
|
ProjectsGrpcRepository(this._client);
|
||||||
|
final ProjectsServiceClient _client;
|
||||||
|
|
||||||
|
ResponseFuture<CreateProjectResponse> createProject(
|
||||||
|
CreateProjectRequest data,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
final response = _client.createProject(data);
|
||||||
|
return response;
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<ListProjectsResponse> listProjects() async* {
|
||||||
|
try {
|
||||||
|
await for (final projects in _client.listProjects(
|
||||||
|
ListProjectsRequest(),
|
||||||
|
)) {
|
||||||
|
yield projects;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:softplayer_dart_proto/accounts/v1/accounts_v1.pbgrpc.dart';
|
import 'package:softplayer_dart_proto/accounts/v1/accounts_v1.pbgrpc.dart';
|
||||||
|
import 'package:softplayer_dart_proto/projects/v1/projects_v1.pbgrpc.dart';
|
||||||
import 'package:softplayer_dart_proto/test/v1/test_v1.pbgrpc.dart';
|
import 'package:softplayer_dart_proto/test/v1/test_v1.pbgrpc.dart';
|
||||||
import 'package:softplayer_web/core/grpc/grpc_auth_interceptor.dart';
|
import 'package:softplayer_web/core/grpc/grpc_auth_interceptor.dart';
|
||||||
import 'package:softplayer_web/core/tokens/application/tokens_application.dart';
|
import 'package:softplayer_web/core/tokens/application/tokens_application.dart';
|
||||||
@@ -41,6 +42,23 @@ final accountsServiceClientProvider = Provider<AccountsServiceClient>((ref) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final projectsServiceClientProvider = Provider<ProjectsServiceClient>((ref) {
|
||||||
|
final channel = ref.watch(grpcChannelProvider);
|
||||||
|
final tokenState = ref.read(tokensControllerProvider).value;
|
||||||
|
if (tokenState == null) {
|
||||||
|
throw Exception("Token state is not initialized");
|
||||||
|
}
|
||||||
|
return ProjectsServiceClient(
|
||||||
|
channel,
|
||||||
|
interceptors: [
|
||||||
|
AuthInterceptor(
|
||||||
|
getAccessToken: tokenState.getAccessToken,
|
||||||
|
getRefreshToken: tokenState.getRefreshToken,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
final publicAccountsServiceClientProvider =
|
final publicAccountsServiceClientProvider =
|
||||||
Provider<PublicAccountsServiceClient>((ref) {
|
Provider<PublicAccountsServiceClient>((ref) {
|
||||||
final channel = ref.watch(grpcChannelProvider);
|
final channel = ref.watch(grpcChannelProvider);
|
||||||
|
|||||||
@@ -38,18 +38,12 @@ class AuthorizationController extends AsyncNotifier<AuthState> {
|
|||||||
|
|
||||||
Future<void> signin(SignInData form) async {
|
Future<void> signin(SignInData form) async {
|
||||||
state = const AsyncLoading();
|
state = const AsyncLoading();
|
||||||
|
|
||||||
sleep(Duration(seconds: 10));
|
|
||||||
state = await AsyncValue.guard(() async {
|
state = await AsyncValue.guard(() async {
|
||||||
final accountsGrpc = ref.read(publicAccountsGrpcProvider);
|
final accountsGrpc = ref.read(publicAccountsGrpcProvider);
|
||||||
final tokenCtrl = ref.read(tokensControllerProvider.notifier);
|
final tokenCtrl = ref.read(tokensControllerProvider.notifier);
|
||||||
try {
|
final response = await accountsGrpc.signIn(form.toProto());
|
||||||
final response = await accountsGrpc.signIn(form.toProto());
|
await tokenCtrl.writeTokenPair(Tokens.fromProto(response.tokenPair));
|
||||||
await tokenCtrl.writeTokenPair(Tokens.fromProto(response.tokenPair));
|
return state.value!.copyWith(isAuthorized: true);
|
||||||
return state.value!.copyWith(isAuthorized: true);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ class _AuthorizationPage extends ConsumerState<AuthorizationPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// ✅ only show decoration if width > 400
|
|
||||||
if (showDecoration) Expanded(flex: 3, child: AuthDecoration()),
|
if (showDecoration) Expanded(flex: 3, child: AuthDecoration()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import 'dart:developer';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:softplayer_web/features/authorization/application/authorization_application.dart';
|
import 'package:softplayer_web/features/authorization/application/authorization_application.dart';
|
||||||
import 'package:softplayer_web/features/authorization/application/sign_in_data.dart';
|
import 'package:softplayer_web/features/authorization/application/sign_in_data.dart';
|
||||||
import 'package:toastification/toastification.dart';
|
|
||||||
|
|
||||||
class LoginForm extends ConsumerStatefulWidget {
|
class LoginForm extends ConsumerStatefulWidget {
|
||||||
const LoginForm({super.key, required this.toggleAuth});
|
const LoginForm({super.key, required this.toggleAuth});
|
||||||
@@ -22,34 +22,32 @@ class _LoginForm extends ConsumerState<LoginForm> {
|
|||||||
|
|
||||||
Future<void> _submitForm() async {
|
Future<void> _submitForm() async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
// If valid, you can use the values
|
|
||||||
final email = emailCtrl.text;
|
final email = emailCtrl.text;
|
||||||
final password = passwordCtrl.text;
|
final password = passwordCtrl.text;
|
||||||
final form = SignInData(email: email, password: password);
|
final form = SignInData(email: email, password: password);
|
||||||
try {
|
await ref.read(authorizationControllerProvider.notifier).signin(form);
|
||||||
await ref.read(authorizationControllerProvider.notifier).signin(form);
|
|
||||||
} catch (e) {
|
|
||||||
if (!mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log(e.toString());
|
|
||||||
toastification.show(
|
|
||||||
context: context,
|
|
||||||
type: ToastificationType.error,
|
|
||||||
style: ToastificationStyle.flatColored,
|
|
||||||
alignment: Alignment.topRight,
|
|
||||||
autoCloseDuration: const Duration(seconds: 4),
|
|
||||||
title: const Text('Authentication failed'),
|
|
||||||
description: Text(e.toString()),
|
|
||||||
showProgressBar: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final state = ref.watch(authorizationControllerProvider);
|
final state = ref.watch(authorizationControllerProvider);
|
||||||
|
|
||||||
|
ref.listenManual(authorizationControllerProvider, (previous, next) {
|
||||||
|
next.whenOrNull(
|
||||||
|
error: (error, stackTrace) {
|
||||||
|
log("test");
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "Authentication failed",
|
||||||
|
toastLength: Toast.LENGTH_LONG,
|
||||||
|
gravity: ToastGravity.TOP, // important for web
|
||||||
|
webPosition: "right", // 👈 important for web
|
||||||
|
webBgColor: "#d32f2f", // required for proper visibility
|
||||||
|
timeInSecForIosWeb: 4,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: ((context, constraints) {
|
builder: ((context, constraints) {
|
||||||
return Stack(
|
return Stack(
|
||||||
@@ -116,6 +114,7 @@ class _LoginForm extends ConsumerState<LoginForm> {
|
|||||||
autofillHints: const [AutofillHints.password],
|
autofillHints: const [AutofillHints.password],
|
||||||
controller: passwordCtrl,
|
controller: passwordCtrl,
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
|
enabled: !state.isLoading,
|
||||||
decoration: InputDecoration(hintText: "Password"),
|
decoration: InputDecoration(hintText: "Password"),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
|
|||||||
@@ -17,15 +17,37 @@ class _DashboardPage extends ConsumerState<DashboardPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ctrl = ref.read(pingControllerProvider.notifier);
|
final ctrl = ref.read(pingControllerProvider.notifier);
|
||||||
log("test");
|
return LayoutBuilder(
|
||||||
return Container(
|
builder: ((context, constraints) {
|
||||||
color: Colors.black87,
|
return Scaffold(
|
||||||
child: ElevatedButton(
|
appBar: AppBar(
|
||||||
onPressed: () {
|
title: Text("Softplayer"),
|
||||||
ctrl.ping();
|
actions: [
|
||||||
},
|
DropdownButtonHideUnderline(
|
||||||
child: Text("pong"),
|
child: DropdownButton<String>(
|
||||||
),
|
items: [
|
||||||
|
DropdownMenuItem(value: "test", child: Text("test")),
|
||||||
|
DropdownMenuItem(value: "test2", child: Text("test2")),
|
||||||
|
],
|
||||||
|
onChanged: (value) => log(value!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
ctrl.ping();
|
||||||
|
},
|
||||||
|
child: Text("pong"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
pubspec.lock
10
pubspec.lock
@@ -264,6 +264,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
fluttertoast:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fluttertoast
|
||||||
|
sha256: "7903c9d5339173497bfecbc23bc4212f5a87e0edfac2e1693fb74465ea67da7e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.1.0"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -856,4 +864,4 @@ packages:
|
|||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.11.5 <4.0.0"
|
dart: ">=3.11.5 <4.0.0"
|
||||||
flutter: ">=3.38.4"
|
flutter: ">=3.41.0"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ dependencies:
|
|||||||
flutter_secure_storage: ^10.2.0
|
flutter_secure_storage: ^10.2.0
|
||||||
jwt_decoder: ^2.0.1
|
jwt_decoder: ^2.0.1
|
||||||
toastification: ^3.2.0
|
toastification: ^3.2.0
|
||||||
|
fluttertoast: ^9.1.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
Reference in New Issue
Block a user