chore: bootstrap flutter reader app skeleton
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../storage/secure_store.dart';
|
||||
|
||||
class ApiClient {
|
||||
ApiClient({
|
||||
required String baseUrl,
|
||||
required SecureStore secureStore,
|
||||
}) : _secureStore = secureStore,
|
||||
dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: baseUrl,
|
||||
connectTimeout: const Duration(seconds: 20),
|
||||
receiveTimeout: const Duration(seconds: 20),
|
||||
headers: const {'Content-Type': 'application/json'},
|
||||
),
|
||||
) {
|
||||
dio.interceptors.add(
|
||||
InterceptorsWrapper(
|
||||
onRequest: (options, handler) async {
|
||||
final token = await _secureStore.getAccessToken();
|
||||
if (token != null && token.isNotEmpty) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
handler.next(options);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final Dio dio;
|
||||
final SecureStore _secureStore;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class LocalStore {
|
||||
static const _kFontSize = 'reader_font_size';
|
||||
static const _kLineHeight = 'reader_line_height';
|
||||
static const _kLetterSpacing = 'reader_letter_spacing';
|
||||
static const _kFontFamily = 'reader_font_family';
|
||||
|
||||
Future<void> saveReadingSettings({
|
||||
required double fontSize,
|
||||
required double lineHeight,
|
||||
required double letterSpacing,
|
||||
required String fontFamily,
|
||||
}) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setDouble(_kFontSize, fontSize);
|
||||
await prefs.setDouble(_kLineHeight, lineHeight);
|
||||
await prefs.setDouble(_kLetterSpacing, letterSpacing);
|
||||
await prefs.setString(_kFontFamily, fontFamily);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getReadingSettings() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return {
|
||||
'fontSize': prefs.getDouble(_kFontSize) ?? 18,
|
||||
'lineHeight': prefs.getDouble(_kLineHeight) ?? 1.8,
|
||||
'letterSpacing': prefs.getDouble(_kLetterSpacing) ?? 0,
|
||||
'fontFamily': prefs.getString(_kFontFamily) ?? 'serif',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
class SecureStore {
|
||||
SecureStore() : _storage = const FlutterSecureStorage();
|
||||
|
||||
static const _kAccessToken = 'access_token';
|
||||
static const _kRefreshToken = 'refresh_token';
|
||||
|
||||
final FlutterSecureStorage _storage;
|
||||
|
||||
Future<void> setAccessToken(String token) =>
|
||||
_storage.write(key: _kAccessToken, value: token);
|
||||
|
||||
Future<String?> getAccessToken() => _storage.read(key: _kAccessToken);
|
||||
|
||||
Future<void> setRefreshToken(String token) =>
|
||||
_storage.write(key: _kRefreshToken, value: token);
|
||||
|
||||
Future<String?> getRefreshToken() => _storage.read(key: _kRefreshToken);
|
||||
|
||||
Future<void> clear() => _storage.deleteAll();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppTheme {
|
||||
AppTheme._();
|
||||
|
||||
static final ThemeData lightTheme = ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: const Color(0xFF155DFC),
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
scaffoldBackgroundColor: const Color(0xFFF7F9FC),
|
||||
appBarTheme: const AppBarTheme(
|
||||
centerTitle: false,
|
||||
backgroundColor: Color(0xFFF7F9FC),
|
||||
foregroundColor: Color(0xFF121826),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user