s
This commit is contained in:
parent
a3cf294070
commit
33c15b1a5f
@ -13,4 +13,8 @@ class ApiEndpoints {
|
|||||||
static const signup = '/auth/signup';
|
static const signup = '/auth/signup';
|
||||||
static const forgotPassword = '/auth/forgot-password';
|
static const forgotPassword = '/auth/forgot-password';
|
||||||
static const userDetails = '/auth/users/';
|
static const userDetails = '/auth/users/';
|
||||||
|
|
||||||
|
///Turn14
|
||||||
|
static const turn14Save = '/auth/turn14/save';
|
||||||
|
static const turn14Status = '/auth/turn14/status';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,9 @@ import 'package:autos/presentation/screens/auth/forgot_password_screen.dart';
|
|||||||
import 'package:autos/presentation/screens/auth/login_screen.dart';
|
import 'package:autos/presentation/screens/auth/login_screen.dart';
|
||||||
import 'package:autos/presentation/screens/auth/sign_up_screen.dart';
|
import 'package:autos/presentation/screens/auth/sign_up_screen.dart';
|
||||||
import 'package:autos/presentation/screens/dashboard/dashboard_screen.dart';
|
import 'package:autos/presentation/screens/dashboard/dashboard_screen.dart';
|
||||||
|
import 'package:autos/presentation/screens/ebay/ebay_screen.dart';
|
||||||
|
import 'package:autos/presentation/screens/store/create_location_screen.dart';
|
||||||
|
import 'package:autos/presentation/screens/store/store.dart';
|
||||||
import 'package:autos/presentation/screens/turn14_screen/turn14_screen.dart';
|
import 'package:autos/presentation/screens/turn14_screen/turn14_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -45,6 +48,15 @@ class AppRouter {
|
|||||||
case AppRoutePaths.turn14:
|
case AppRoutePaths.turn14:
|
||||||
return slideRoute(const Turn14Screen());
|
return slideRoute(const Turn14Screen());
|
||||||
|
|
||||||
|
case AppRoutePaths.ebay:
|
||||||
|
return slideRoute(EbayScreen());
|
||||||
|
|
||||||
|
case AppRoutePaths.store:
|
||||||
|
return slideRoute(StoreScreen());
|
||||||
|
|
||||||
|
case AppRoutePaths.createStoreLocation:
|
||||||
|
return slideRoute(CreateLocationScreen());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return _defaultFallback(settings);
|
return _defaultFallback(settings);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,4 +4,7 @@ class AppRoutePaths {
|
|||||||
static const forgotPassword = '/forgotPassword';
|
static const forgotPassword = '/forgotPassword';
|
||||||
static const dashboard = '/dashboard';
|
static const dashboard = '/dashboard';
|
||||||
static const turn14 = '/turn14';
|
static const turn14 = '/turn14';
|
||||||
|
static const ebay = '/ebay';
|
||||||
|
static const store = '/store';
|
||||||
|
static const createStoreLocation = '/createStoreLocation';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,8 +59,8 @@ class SideMenu extends ConsumerWidget {
|
|||||||
// --- INTEGRATIONS ---
|
// --- INTEGRATIONS ---
|
||||||
_sectionHeader("INTEGRATIONS"),
|
_sectionHeader("INTEGRATIONS"),
|
||||||
_menuItem(context, "⚡", "Turn14", AppRoutePaths.turn14),
|
_menuItem(context, "⚡", "Turn14", AppRoutePaths.turn14),
|
||||||
_menuItem(context, "🛍️", "eBay", 'ebay'),
|
_menuItem(context, "🛍️", "eBay", AppRoutePaths.ebay),
|
||||||
_menuItem(context, "🛒", "Store", 'store'),
|
_menuItem(context, "🛒", "Store", AppRoutePaths.store),
|
||||||
|
|
||||||
// --- MANAGE ---
|
// --- MANAGE ---
|
||||||
_sectionHeader("MANAGE"),
|
_sectionHeader("MANAGE"),
|
||||||
|
|||||||
98
lib/data/models/turn14_model.dart
Normal file
98
lib/data/models/turn14_model.dart
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:autos/domain/entities/turn14.dart';
|
||||||
|
|
||||||
|
class Turn14Response {
|
||||||
|
final String code;
|
||||||
|
final String message;
|
||||||
|
final String userId;
|
||||||
|
final String accessToken;
|
||||||
|
|
||||||
|
const Turn14Response({
|
||||||
|
required this.code,
|
||||||
|
required this.message,
|
||||||
|
required this.userId,
|
||||||
|
required this.accessToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Turn14Response.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Turn14Response(
|
||||||
|
code: json['code'] ?? '',
|
||||||
|
message: json['message'] ?? '',
|
||||||
|
userId: json['userid'] ?? '',
|
||||||
|
accessToken: json['access_token'] ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'code': code,
|
||||||
|
'message': message,
|
||||||
|
'userid': userId,
|
||||||
|
'access_token': accessToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert model → raw JSON string
|
||||||
|
String toRawJson() => jsonEncode(toJson());
|
||||||
|
|
||||||
|
/// Convert raw JSON string → model
|
||||||
|
factory Turn14Response.fromRawJson(String raw) =>
|
||||||
|
Turn14Response.fromJson(jsonDecode(raw));
|
||||||
|
|
||||||
|
/// Convert Response → Domain Entity
|
||||||
|
Turn14Entity toEntity() {
|
||||||
|
return Turn14Entity(
|
||||||
|
code: code,
|
||||||
|
message: message,
|
||||||
|
userId: userId,
|
||||||
|
accessToken: accessToken,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Turn14Response(code: $code, message: $message, userId: $userId, accessToken: $accessToken)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Turn14StatusModel {
|
||||||
|
final String userId;
|
||||||
|
final bool hasCredentials;
|
||||||
|
final String? clientId;
|
||||||
|
final String? clientSecret;
|
||||||
|
final String? accessToken;
|
||||||
|
final String? expiresIn;
|
||||||
|
|
||||||
|
Turn14StatusModel({
|
||||||
|
required this.userId,
|
||||||
|
required this.hasCredentials,
|
||||||
|
this.clientId,
|
||||||
|
this.clientSecret,
|
||||||
|
this.accessToken,
|
||||||
|
this.expiresIn,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Turn14StatusModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Turn14StatusModel(
|
||||||
|
userId: json["userid"],
|
||||||
|
hasCredentials: json["hasCredentials"] ?? false,
|
||||||
|
clientId: json["credentials"]?["turn14clientid"],
|
||||||
|
clientSecret: json["credentials"]?["turn14clientsecret"],
|
||||||
|
accessToken: json["tokenInfo"]?["access_token"],
|
||||||
|
expiresIn: json["tokenInfo"]?["expires_in"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Turn14StatusEntity toEntity() {
|
||||||
|
return Turn14StatusEntity(
|
||||||
|
userId: userId,
|
||||||
|
hasCredentials: hasCredentials,
|
||||||
|
clientId: clientId,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
accessToken: accessToken,
|
||||||
|
expiresIn: expiresIn,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
lib/data/repositories/turn14_repository_impl.dart
Normal file
77
lib/data/repositories/turn14_repository_impl.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import 'package:autos/core/constants/api_endpoints.dart';
|
||||||
|
import 'package:autos/data/models/turn14_model.dart';
|
||||||
|
import 'package:autos/data/sources/remote/api_service.dart';
|
||||||
|
import 'package:autos/domain/entities/turn14.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
abstract class Turn14Repository {
|
||||||
|
/// Save Turn14 credentials
|
||||||
|
Future<Turn14Entity> save({
|
||||||
|
required String userId,
|
||||||
|
required String clientId,
|
||||||
|
required String clientSecret,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Turn14RepositoryImpl implements Turn14Repository {
|
||||||
|
final ApiService _apiService;
|
||||||
|
|
||||||
|
Turn14RepositoryImpl(this._apiService);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Turn14Entity> save({
|
||||||
|
required String userId,
|
||||||
|
required String clientId,
|
||||||
|
required String clientSecret,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await _apiService.post(ApiEndpoints.turn14Save, {
|
||||||
|
"userid": userId,
|
||||||
|
"turn14clientid": clientId,
|
||||||
|
"turn14clientsecret": clientSecret,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check status
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = response.data;
|
||||||
|
|
||||||
|
if (data['code'] == "TURN14_SAVED") {
|
||||||
|
/// Convert Response → Entity
|
||||||
|
return Turn14Response.fromJson(data).toEntity();
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
data['message'] ?? "Failed to save Turn14 credentials",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception("Server error: ${response.statusCode}");
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
throw Exception("Network error: ${e.message}");
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception("Unexpected error: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Turn14StatusEntity> status(String userId) async {
|
||||||
|
try {
|
||||||
|
final response = await _apiService.post(ApiEndpoints.turn14Status, {
|
||||||
|
"userid": userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = response.data;
|
||||||
|
|
||||||
|
if (data["code"] == "TURN14_STATUS") {
|
||||||
|
return Turn14StatusModel.fromJson(data).toEntity();
|
||||||
|
} else {
|
||||||
|
throw Exception(data["message"] ?? "Failed to fetch Turn14 status");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception("Server error: ${response.statusCode}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception("Network/Unexpected error: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
lib/domain/entities/turn14.dart
Normal file
31
lib/domain/entities/turn14.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
class Turn14Entity {
|
||||||
|
final String code;
|
||||||
|
final String message;
|
||||||
|
final String userId;
|
||||||
|
final String accessToken;
|
||||||
|
|
||||||
|
const Turn14Entity({
|
||||||
|
required this.code,
|
||||||
|
required this.message,
|
||||||
|
required this.userId,
|
||||||
|
required this.accessToken,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Turn14StatusEntity {
|
||||||
|
final String userId;
|
||||||
|
final bool hasCredentials;
|
||||||
|
final String? clientId;
|
||||||
|
final String? clientSecret;
|
||||||
|
final String? accessToken;
|
||||||
|
final String? expiresIn;
|
||||||
|
|
||||||
|
Turn14StatusEntity({
|
||||||
|
required this.userId,
|
||||||
|
required this.hasCredentials,
|
||||||
|
this.clientId,
|
||||||
|
this.clientSecret,
|
||||||
|
this.accessToken,
|
||||||
|
this.expiresIn,
|
||||||
|
});
|
||||||
|
}
|
||||||
91
lib/presentation/providers/turn14_provider.dart
Normal file
91
lib/presentation/providers/turn14_provider.dart
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:autos/data/models/turn14_model.dart';
|
||||||
|
import 'package:autos/data/repositories/turn14_repository_impl.dart';
|
||||||
|
import 'package:autos/data/sources/remote/api_service.dart';
|
||||||
|
import 'package:autos/domain/entities/turn14.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_riverpod/legacy.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
|
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
/// Service Providers
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
|
||||||
|
final turn14ApiServiceProvider =
|
||||||
|
Provider<ApiService>((ref) => ApiService());
|
||||||
|
|
||||||
|
final turn14RepositoryProvider = Provider<Turn14RepositoryImpl>((ref) {
|
||||||
|
return Turn14RepositoryImpl(ref.read(turn14ApiServiceProvider));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
/// Turn14 Notifier
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
|
||||||
|
class Turn14Notifier extends StateNotifier<AsyncValue<Turn14Entity?>> {
|
||||||
|
final Turn14RepositoryImpl repository;
|
||||||
|
final _storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
|
static const _turn14StorageKey = "turn14_credentials";
|
||||||
|
|
||||||
|
Turn14Notifier(this.repository) : super(const AsyncValue.data(null));
|
||||||
|
|
||||||
|
/// Save Turn14 credentials
|
||||||
|
Future<void> saveCredentials({
|
||||||
|
required String userId,
|
||||||
|
required String clientId,
|
||||||
|
required String clientSecret,
|
||||||
|
}) async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await repository.save(
|
||||||
|
userId: userId,
|
||||||
|
clientId: clientId,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
);
|
||||||
|
|
||||||
|
// if (response is Turn14Response) {
|
||||||
|
// await _storage.write(
|
||||||
|
// key: _turn14StorageKey,
|
||||||
|
// value: response.toRawJson(),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
state = AsyncValue.data(response);
|
||||||
|
} catch (e, st) {
|
||||||
|
state = AsyncValue.error(e, st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load saved Turn14 credentials
|
||||||
|
Future<void> loadSavedCredentials() async {
|
||||||
|
final saved = await _storage.read(key: _turn14StorageKey);
|
||||||
|
if (saved == null) return;
|
||||||
|
|
||||||
|
final decoded = jsonDecode(saved);
|
||||||
|
final model = Turn14Response.fromJson(decoded);
|
||||||
|
|
||||||
|
state = AsyncValue.data(model as Turn14Entity?);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear saved Turn14 data
|
||||||
|
Future<void> clear() async {
|
||||||
|
await _storage.delete(key: _turn14StorageKey);
|
||||||
|
state = const AsyncValue.data(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
/// Riverpod Provider
|
||||||
|
/// ------------------------------------------------------------
|
||||||
|
|
||||||
|
final turn14Provider =
|
||||||
|
StateNotifierProvider<Turn14Notifier, AsyncValue<Turn14Entity?>>((ref) {
|
||||||
|
final repository = ref.read(turn14RepositoryProvider);
|
||||||
|
return Turn14Notifier(repository);
|
||||||
|
});
|
||||||
124
lib/presentation/screens/ebay/ebay_screen.dart
Normal file
124
lib/presentation/screens/ebay/ebay_screen.dart
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:autos/core/widgets/hamburger_button.dart';
|
||||||
|
import 'package:autos/core/widgets/side_menu.dart';
|
||||||
|
|
||||||
|
class EbayScreen extends StatefulWidget {
|
||||||
|
const EbayScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EbayScreen> createState() => _EbayScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EbayScreenState extends State<EbayScreen> {
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
String selected = "ebay";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double topPadding = MediaQuery.of(context).padding.top + 16;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
key: _scaffoldKey,
|
||||||
|
drawer: SideMenu(
|
||||||
|
selected: selected,
|
||||||
|
onItemSelected: (key) {
|
||||||
|
setState(() => selected = key);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// backgroundColor: const Color(0xFFEFFAFF),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
/// TITLE
|
||||||
|
Positioned(
|
||||||
|
top: topPadding,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"eBay Settings",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 26,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// MAIN BOX UI
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.90,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 40),
|
||||||
|
margin: EdgeInsets.only(top: topPadding + 60),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 25,
|
||||||
|
offset: const Offset(0, 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
/// Description
|
||||||
|
Text(
|
||||||
|
"Connect your eBay store to enable product sync, inventory updates, and order flow.",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.black54,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
|
||||||
|
/// BUTTON
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Add eBay authorization flow
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF00CFFF),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"Connect your eBay store",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"You'll be redirected to eBay to authorize access, then returned here.",
|
||||||
|
style: const TextStyle(fontSize: 13, color: Colors.black45),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// HAMBURGER BUTTON
|
||||||
|
HamburgerButton(scaffoldKey: _scaffoldKey),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
215
lib/presentation/screens/store/create_location_screen.dart
Normal file
215
lib/presentation/screens/store/create_location_screen.dart
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CreateLocationScreen extends StatefulWidget {
|
||||||
|
const CreateLocationScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CreateLocationScreen> createState() => _CreateLocationScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateLocationScreenState extends State<CreateLocationScreen> {
|
||||||
|
// Controllers
|
||||||
|
final TextEditingController storeName = TextEditingController();
|
||||||
|
final TextEditingController phone = TextEditingController();
|
||||||
|
final TextEditingController address1 = TextEditingController();
|
||||||
|
final TextEditingController city = TextEditingController();
|
||||||
|
final TextEditingController stateCtrl = TextEditingController();
|
||||||
|
final TextEditingController postalCode = TextEditingController();
|
||||||
|
final TextEditingController country = TextEditingController();
|
||||||
|
final TextEditingController timeZone = TextEditingController(text: "America/New_York");
|
||||||
|
TimeOfDay openTime = const TimeOfDay(hour: 9, minute: 0);
|
||||||
|
TimeOfDay closeTime = const TimeOfDay(hour: 18, minute: 0);
|
||||||
|
|
||||||
|
Future<void> pickTime({required bool isOpen}) async {
|
||||||
|
final TimeOfDay? picked = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: isOpen ? openTime : closeTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (picked != null) {
|
||||||
|
setState(() {
|
||||||
|
if (isOpen) openTime = picked;
|
||||||
|
else closeTime = picked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFFEFFAFF),
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text("Create New Location"),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
elevation: 0,
|
||||||
|
foregroundColor: Colors.black,
|
||||||
|
),
|
||||||
|
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(30),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 20,
|
||||||
|
offset: const Offset(0, 10),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_input("Store Name *", "Enter store name", storeName),
|
||||||
|
_input("Phone *", "Enter phone number", phone),
|
||||||
|
_input("Address Line 1 *", "Enter address", address1),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: _input("City *", "City", city)),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(child: _input("State *", "State", stateCtrl)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: _input("Postal Code *", "Postal Code", postalCode)),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(child: _input("Country *", "Country Code (e.g. US)", country)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
_input("Time Zone *", "America/New_York", timeZone),
|
||||||
|
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _timePicker(
|
||||||
|
label: "Open Time *",
|
||||||
|
time: openTime,
|
||||||
|
onTap: () => pickTime(isOpen: true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: _timePicker(
|
||||||
|
label: "Close Time *",
|
||||||
|
time: closeTime,
|
||||||
|
onTap: () => pickTime(isOpen: false),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
final json = {
|
||||||
|
"store_name": storeName.text,
|
||||||
|
"phone": phone.text,
|
||||||
|
"address1": address1.text,
|
||||||
|
"city": city.text,
|
||||||
|
"state": stateCtrl.text,
|
||||||
|
"postal_code": postalCode.text,
|
||||||
|
"country": country.text,
|
||||||
|
"timezone": timeZone.text,
|
||||||
|
"open_time": openTime.format(context),
|
||||||
|
"close_time": closeTime.format(context),
|
||||||
|
};
|
||||||
|
|
||||||
|
print("📦 LOCATION JSON → $json");
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF00CFFF),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"Save & Console JSON",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reusable TextField
|
||||||
|
Widget _input(String label, String hint, TextEditingController controller) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 18),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(label,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14)),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
TextField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: hint,
|
||||||
|
filled: true,
|
||||||
|
fillColor: const Color(0xFFF0F6FF),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Picker Widget
|
||||||
|
Widget _timePicker({
|
||||||
|
required String label,
|
||||||
|
required TimeOfDay time,
|
||||||
|
required VoidCallback onTap,
|
||||||
|
}) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(label,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14)),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 18),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF0F6FF),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(time.format(context),
|
||||||
|
style: const TextStyle(fontSize: 16)),
|
||||||
|
const Spacer(),
|
||||||
|
const Icon(Icons.access_time, size: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
131
lib/presentation/screens/store/store.dart
Normal file
131
lib/presentation/screens/store/store.dart
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import 'package:autos/core/routing/route_paths.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:autos/core/widgets/hamburger_button.dart';
|
||||||
|
import 'package:autos/core/widgets/side_menu.dart';
|
||||||
|
|
||||||
|
class StoreScreen extends StatefulWidget {
|
||||||
|
const StoreScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StoreScreen> createState() => _StoreScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StoreScreenState extends State<StoreScreen> {
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
String selected = "ebay";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double topPadding = MediaQuery.of(context).padding.top + 16;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
key: _scaffoldKey,
|
||||||
|
drawer: SideMenu(
|
||||||
|
selected: selected,
|
||||||
|
onItemSelected: (key) {
|
||||||
|
setState(() => selected = key);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
/// TITLE
|
||||||
|
Positioned(
|
||||||
|
top: topPadding,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: const Center(
|
||||||
|
child: Text(
|
||||||
|
"eBay Locations",
|
||||||
|
style: TextStyle(fontSize: 26, fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// MAIN WITH BUTTONS
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.90,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 40),
|
||||||
|
margin: EdgeInsets.only(top: topPadding + 60),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 25,
|
||||||
|
offset: const Offset(0, 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
/// SAVE SELECTED BUTTON
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Save Selected Flow
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF00CFFF),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"Save Selected",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
/// CREATE NEW LOCATION BUTTON
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
AppRoutePaths.createStoreLocation,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF00CFFF),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"Create New Location",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// HAMBURGER BUTTON
|
||||||
|
HamburgerButton(scaffoldKey: _scaffoldKey),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,8 +2,10 @@ import 'package:autos/core/theme/app_typography.dart';
|
|||||||
import 'package:autos/core/widgets/hamburger_button.dart';
|
import 'package:autos/core/widgets/hamburger_button.dart';
|
||||||
import 'package:autos/core/widgets/side_menu.dart';
|
import 'package:autos/core/widgets/side_menu.dart';
|
||||||
import 'package:autos/presentation/providers/user_provider.dart';
|
import 'package:autos/presentation/providers/user_provider.dart';
|
||||||
|
import 'package:autos/presentation/providers/turn14_provider.dart';
|
||||||
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';
|
||||||
|
|
||||||
class Turn14Screen extends ConsumerStatefulWidget {
|
class Turn14Screen extends ConsumerStatefulWidget {
|
||||||
const Turn14Screen({super.key});
|
const Turn14Screen({super.key});
|
||||||
@ -16,9 +18,16 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
String selected = 'turn14';
|
String selected = 'turn14';
|
||||||
|
|
||||||
|
// controllers
|
||||||
|
final TextEditingController clientIdController = TextEditingController();
|
||||||
|
final TextEditingController clientSecretController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final user = ref.watch(userDetailsProvider);
|
final asyncUser = ref.watch(userDetailsProvider);
|
||||||
|
final turn14State = ref.watch(turn14Provider);
|
||||||
|
|
||||||
|
final user = asyncUser.value;
|
||||||
final double topPadding = MediaQuery.of(context).padding.top + 16;
|
final double topPadding = MediaQuery.of(context).padding.top + 16;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -46,13 +55,13 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
/// Main Scrollable UI
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
padding: EdgeInsets.fromLTRB(16, topPadding + 55, 16, 20),
|
padding: EdgeInsets.fromLTRB(16, topPadding + 55, 16, 20),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Description Row
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("⚡", style: const TextStyle(fontSize: 28)),
|
Text("⚡", style: const TextStyle(fontSize: 28)),
|
||||||
@ -70,21 +79,16 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Client ID Input
|
_inputField(label: "Client ID", controller: clientIdController),
|
||||||
_inputField(
|
|
||||||
label: "Client ID",
|
|
||||||
controller: TextEditingController(),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Secret Key Input With Eye Icon
|
|
||||||
_passwordField(
|
_passwordField(
|
||||||
label: "Secret Key",
|
label: "Secret Key",
|
||||||
controller: TextEditingController(),
|
controller: clientSecretController,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 25),
|
const SizedBox(height: 25),
|
||||||
|
|
||||||
// Save Button
|
/// SAVE BUTTON
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
@ -95,65 +99,70 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
),
|
),
|
||||||
backgroundColor: const Color(0xFF00C9FF),
|
backgroundColor: const Color(0xFF00C9FF),
|
||||||
),
|
),
|
||||||
onPressed: () {},
|
onPressed: turn14State.isLoading
|
||||||
child: const Text(
|
? null
|
||||||
"Save Credentials",
|
: () async {
|
||||||
style: TextStyle(
|
if (user == null) {
|
||||||
color: Colors.white,
|
Fluttertoast.showToast(
|
||||||
fontWeight: FontWeight.bold,
|
msg: "⚠️ User not found",
|
||||||
fontSize: 16,
|
toastLength: Toast.LENGTH_LONG,
|
||||||
),
|
gravity: ToastGravity.BOTTOM,
|
||||||
),
|
backgroundColor: Colors.red,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientIdController.text.trim().isEmpty ||
|
||||||
|
clientSecretController.text.trim().isEmpty) {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "⚠️ Please fill all fields",
|
||||||
|
toastLength: Toast.LENGTH_LONG,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
backgroundColor: Colors.orange,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ref
|
||||||
|
.read(turn14Provider.notifier)
|
||||||
|
.saveCredentials(
|
||||||
|
userId: user.id,
|
||||||
|
clientId: clientIdController.text.trim(),
|
||||||
|
clientSecret:
|
||||||
|
clientSecretController.text.trim(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "✅ Turn14 Credentials Saved Successfully",
|
||||||
|
toastLength: Toast.LENGTH_LONG,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: turn14State.isLoading
|
||||||
|
? const CircularProgressIndicator(color: Colors.white)
|
||||||
|
: const Text(
|
||||||
|
"Save Credentials",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Info Box
|
_infoBox(),
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFFE8F1FF),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: const [
|
|
||||||
Icon(Icons.info, color: Colors.blue),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(
|
|
||||||
"No credentials saved yet.",
|
|
||||||
style: TextStyle(color: Colors.black87),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
_tipsBox(),
|
||||||
// Tips Box
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFFE8FCFF),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: const [
|
|
||||||
Text(
|
|
||||||
"💡 Connection Tips",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
Text("• Ensure your credentials are valid and active."),
|
|
||||||
Text("• Credentials are encrypted before saving."),
|
|
||||||
Text("• Contact Turn14 support for API setup help."),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -164,6 +173,7 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// UI COMPONENTS
|
||||||
Widget _inputField({
|
Widget _inputField({
|
||||||
required String label,
|
required String label,
|
||||||
required TextEditingController controller,
|
required TextEditingController controller,
|
||||||
@ -224,4 +234,49 @@ class _Turn14ScreenState extends ConsumerState<Turn14Screen> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _infoBox() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFE8F1FF),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Icon(Icons.info, color: Colors.blue),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
"No credentials saved yet.",
|
||||||
|
style: TextStyle(color: Colors.black87),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _tipsBox() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFE8FCFF),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: const [
|
||||||
|
Text(
|
||||||
|
"💡 Connection Tips",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text("• Ensure your credentials are valid and active."),
|
||||||
|
Text("• Credentials are encrypted before saving."),
|
||||||
|
Text("• Contact Turn14 support for API setup help."),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
pubspec.lock
72
pubspec.lock
@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.7.1"
|
version: "7.7.1"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.7"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -49,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.4"
|
||||||
cli_config:
|
cli_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -57,6 +73,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.2.0"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.2"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -214,6 +238,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.0"
|
version: "0.6.0"
|
||||||
|
flutter_launcher_icons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_launcher_icons
|
||||||
|
sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.14.4"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -328,6 +360,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.2"
|
version: "4.1.2"
|
||||||
|
image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.4"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -344,6 +384,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.7"
|
version: "0.6.7"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.9.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -488,6 +536,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -512,6 +568,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "1.5.2"
|
||||||
|
posix:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: posix
|
||||||
|
sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.3"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -733,6 +797,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.6.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
10
pubspec.yaml
10
pubspec.yaml
@ -20,6 +20,7 @@ dependencies:
|
|||||||
fluttertoast: ^9.0.0
|
fluttertoast: ^9.0.0
|
||||||
flutter_secure_storage: ^9.2.4
|
flutter_secure_storage: ^9.2.4
|
||||||
youtube_player_flutter: ^9.1.3
|
youtube_player_flutter: ^9.1.3
|
||||||
|
flutter_launcher_icons: ^0.14.4
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -48,4 +49,11 @@ flutter:
|
|||||||
- asset: assets/fonts/Nunito-SemiBold.ttf
|
- asset: assets/fonts/Nunito-SemiBold.ttf
|
||||||
weight: 600
|
weight: 600
|
||||||
- asset: assets/fonts/Nunito-Bold.ttf
|
- asset: assets/fonts/Nunito-Bold.ttf
|
||||||
weight: 700
|
weight: 700
|
||||||
|
|
||||||
|
flutter_launcher_icons:
|
||||||
|
android: true
|
||||||
|
ios: true
|
||||||
|
image_path: "assets/auth/autos_transp.png"
|
||||||
|
adaptive_icon_background: "#FFFFFF"
|
||||||
|
adaptive_icon_foreground: "assets/auth/autos_transp.png"
|
||||||
Loading…
x
Reference in New Issue
Block a user