mirror of
https://github.com/bettercoding-dev/flutter-jwt-auth.git
synced 2025-05-17 09:35:54 +08:00
implement jwt flow
This commit is contained in:
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "shelf-jwt-test-server"]
|
||||
path = shelf-jwt-test-server
|
||||
url = git@github.com:bettercoding-dev/shelf-jwt-test-server.git
|
||||
[submodule "server/shelf-jwt-test-server"]
|
||||
path = server/shelf-jwt-test-server
|
||||
url = git@github.com:bettercoding-dev/shelf-jwt-test-server.git
|
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
44
ios/Podfile
Normal file
44
ios/Podfile
Normal file
@ -0,0 +1,44 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '12.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
22
ios/Podfile.lock
Normal file
22
ios/Podfile.lock
Normal file
@ -0,0 +1,22 @@
|
||||
PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
|
||||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
||||
|
||||
COCOAPODS: 1.15.2
|
@ -8,6 +8,8 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
1646D1EEE5DF6FE5BAD39A15 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91D9E65E8A5E264762FF8B1A /* Pods_RunnerTests.framework */; };
|
||||
261FEC04840279EDAC19C313 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A02DCFF8620D3F72F79A3840 /* Pods_Runner.framework */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
@ -40,14 +42,19 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
132BB70143962167930A6E31 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
33E36FBF3F48DA58460C0E68 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
4E08E345669F7FAB9ABC4F0B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
8F0EC2398A99C280A77C69B2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
91D9E65E8A5E264762FF8B1A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -55,13 +62,25 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A02DCFF8620D3F72F79A3840 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C1A8494C902218FF87CAC30F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
ED0E05E65940F20CD74F80A1 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
595AB5F2277E9FB394A4FBFD /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1646D1EEE5DF6FE5BAD39A15 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
261FEC04840279EDAC19C313 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -94,6 +113,8 @@
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
A25A5221F0DECAE777A7C39A /* Pods */,
|
||||
C3358ABD8B73863554D6CBCE /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -121,6 +142,28 @@
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A25A5221F0DECAE777A7C39A /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8F0EC2398A99C280A77C69B2 /* Pods-Runner.debug.xcconfig */,
|
||||
33E36FBF3F48DA58460C0E68 /* Pods-Runner.release.xcconfig */,
|
||||
4E08E345669F7FAB9ABC4F0B /* Pods-Runner.profile.xcconfig */,
|
||||
ED0E05E65940F20CD74F80A1 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
132BB70143962167930A6E31 /* Pods-RunnerTests.release.xcconfig */,
|
||||
C1A8494C902218FF87CAC30F /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C3358ABD8B73863554D6CBCE /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A02DCFF8620D3F72F79A3840 /* Pods_Runner.framework */,
|
||||
91D9E65E8A5E264762FF8B1A /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -128,8 +171,10 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
7EE5E162952D2EF1724B6F3C /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
595AB5F2277E9FB394A4FBFD /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -145,12 +190,14 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
C1E76FD3B568DD3E0EEA9500 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
26958E994E7C110BC936614B /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -222,6 +269,23 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
26958E994E7C110BC936614B /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@ -238,6 +302,28 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
7EE5E162952D2EF1724B6F3C /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@ -253,6 +339,28 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
C1E76FD3B568DD3E0EEA9500 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@ -362,7 +470,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 79C8VHVD3P;
|
||||
DEVELOPMENT_TEAM = 78A8AZ76DR;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -379,6 +487,7 @@
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = ED0E05E65940F20CD74F80A1 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@ -396,6 +505,7 @@
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 132BB70143962167930A6E31 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@ -411,6 +521,7 @@
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = C1A8494C902218FF87CAC30F /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@ -542,7 +653,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 79C8VHVD3P;
|
||||
DEVELOPMENT_TEAM = 78A8AZ76DR;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -565,7 +676,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 79C8VHVD3P;
|
||||
DEVELOPMENT_TEAM = 78A8AZ76DR;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
25
lib/auth/client/auth_client.dart
Normal file
25
lib/auth/client/auth_client.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_jwt_auth/auth/client/login_request.dart';
|
||||
import 'package:flutter_jwt_auth/auth/client/refresh_token_request.dart';
|
||||
import 'package:flutter_jwt_auth/auth/model/auth_data.dart';
|
||||
import 'package:flutter_jwt_auth/global_providers.dart';
|
||||
|
||||
part 'auth_client.g.dart';
|
||||
|
||||
@riverpod
|
||||
AuthClient authClient(AuthClientRef ref) => AuthClient(
|
||||
ref.watch(dioProvider),
|
||||
);
|
||||
|
||||
@RestApi()
|
||||
abstract class AuthClient {
|
||||
factory AuthClient(Dio dio) = _AuthClient;
|
||||
|
||||
@POST('/login')
|
||||
Future<AuthData> login(@Body() LoginRequest request);
|
||||
|
||||
@POST('/refresh')
|
||||
Future<AuthData> refresh(@Body() RefreshTokenRequest request);
|
||||
}
|
140
lib/auth/client/auth_client.g.dart
Normal file
140
lib/auth/client/auth_client.g.dart
Normal file
@ -0,0 +1,140 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_client.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RetrofitGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element
|
||||
|
||||
class _AuthClient implements AuthClient {
|
||||
_AuthClient(
|
||||
this._dio, {
|
||||
this.baseUrl,
|
||||
this.errorLogger,
|
||||
});
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
String? baseUrl;
|
||||
|
||||
final ParseErrorLogger? errorLogger;
|
||||
|
||||
@override
|
||||
Future<AuthData> login(LoginRequest request) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = request;
|
||||
final _options = _setStreamType<AuthData>(Options(
|
||||
method: 'POST',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/login',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
)));
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late AuthData _value;
|
||||
try {
|
||||
_value = AuthData.fromJson(_result.data!);
|
||||
} on Object catch (e, s) {
|
||||
errorLogger?.logError(e, s, _options);
|
||||
rethrow;
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AuthData> refresh(RefreshTokenRequest request) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = request;
|
||||
final _options = _setStreamType<AuthData>(Options(
|
||||
method: 'POST',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/refresh',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
)));
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late AuthData _value;
|
||||
try {
|
||||
_value = AuthData.fromJson(_result.data!);
|
||||
} on Object catch (e, s) {
|
||||
errorLogger?.logError(e, s, _options);
|
||||
rethrow;
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
requestOptions.responseType == ResponseType.stream)) {
|
||||
if (T == String) {
|
||||
requestOptions.responseType = ResponseType.plain;
|
||||
} else {
|
||||
requestOptions.responseType = ResponseType.json;
|
||||
}
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
String _combineBaseUrls(
|
||||
String dioBaseUrl,
|
||||
String? baseUrl,
|
||||
) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty) {
|
||||
return dioBaseUrl;
|
||||
}
|
||||
|
||||
final url = Uri.parse(baseUrl);
|
||||
|
||||
if (url.isAbsolute) {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$authClientHash() => r'cd6faf293e6975a9091a92d7534d8e4a7d33284b';
|
||||
|
||||
/// See also [authClient].
|
||||
@ProviderFor(authClient)
|
||||
final authClientProvider = AutoDisposeProvider<AuthClient>.internal(
|
||||
authClient,
|
||||
name: r'authClientProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$authClientHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef AuthClientRef = AutoDisposeProviderRef<AuthClient>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
15
lib/auth/client/login_request.dart
Normal file
15
lib/auth/client/login_request.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'login_request.freezed.dart';
|
||||
part 'login_request.g.dart';
|
||||
|
||||
@freezed
|
||||
class LoginRequest with _$LoginRequest {
|
||||
const factory LoginRequest({
|
||||
required String username,
|
||||
}) = _LoginRequest;
|
||||
|
||||
factory LoginRequest.fromJson(Map<String, dynamic> json) =>
|
||||
_$LoginRequestFromJson(json);
|
||||
}
|
174
lib/auth/client/login_request.freezed.dart
Normal file
174
lib/auth/client/login_request.freezed.dart
Normal file
@ -0,0 +1,174 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'login_request.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
LoginRequest _$LoginRequestFromJson(Map<String, dynamic> json) {
|
||||
return _LoginRequest.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LoginRequest {
|
||||
String get username => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LoginRequest to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LoginRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LoginRequestCopyWith<LoginRequest> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LoginRequestCopyWith<$Res> {
|
||||
factory $LoginRequestCopyWith(
|
||||
LoginRequest value, $Res Function(LoginRequest) then) =
|
||||
_$LoginRequestCopyWithImpl<$Res, LoginRequest>;
|
||||
@useResult
|
||||
$Res call({String username});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LoginRequestCopyWithImpl<$Res, $Val extends LoginRequest>
|
||||
implements $LoginRequestCopyWith<$Res> {
|
||||
_$LoginRequestCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LoginRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? username = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
username: null == username
|
||||
? _value.username
|
||||
: username // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoginRequestImplCopyWith<$Res>
|
||||
implements $LoginRequestCopyWith<$Res> {
|
||||
factory _$$LoginRequestImplCopyWith(
|
||||
_$LoginRequestImpl value, $Res Function(_$LoginRequestImpl) then) =
|
||||
__$$LoginRequestImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String username});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoginRequestImplCopyWithImpl<$Res>
|
||||
extends _$LoginRequestCopyWithImpl<$Res, _$LoginRequestImpl>
|
||||
implements _$$LoginRequestImplCopyWith<$Res> {
|
||||
__$$LoginRequestImplCopyWithImpl(
|
||||
_$LoginRequestImpl _value, $Res Function(_$LoginRequestImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LoginRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? username = null,
|
||||
}) {
|
||||
return _then(_$LoginRequestImpl(
|
||||
username: null == username
|
||||
? _value.username
|
||||
: username // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LoginRequestImpl with DiagnosticableTreeMixin implements _LoginRequest {
|
||||
const _$LoginRequestImpl({required this.username});
|
||||
|
||||
factory _$LoginRequestImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LoginRequestImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String username;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'LoginRequest(username: $username)';
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'LoginRequest'))
|
||||
..add(DiagnosticsProperty('username', username));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LoginRequestImpl &&
|
||||
(identical(other.username, username) ||
|
||||
other.username == username));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, username);
|
||||
|
||||
/// Create a copy of LoginRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LoginRequestImplCopyWith<_$LoginRequestImpl> get copyWith =>
|
||||
__$$LoginRequestImplCopyWithImpl<_$LoginRequestImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LoginRequestImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LoginRequest implements LoginRequest {
|
||||
const factory _LoginRequest({required final String username}) =
|
||||
_$LoginRequestImpl;
|
||||
|
||||
factory _LoginRequest.fromJson(Map<String, dynamic> json) =
|
||||
_$LoginRequestImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get username;
|
||||
|
||||
/// Create a copy of LoginRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LoginRequestImplCopyWith<_$LoginRequestImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
17
lib/auth/client/login_request.g.dart
Normal file
17
lib/auth/client/login_request.g.dart
Normal file
@ -0,0 +1,17 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'login_request.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$LoginRequestImpl _$$LoginRequestImplFromJson(Map<String, dynamic> json) =>
|
||||
_$LoginRequestImpl(
|
||||
username: json['username'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LoginRequestImplToJson(_$LoginRequestImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'username': instance.username,
|
||||
};
|
14
lib/auth/client/refresh_token_request.dart
Normal file
14
lib/auth/client/refresh_token_request.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'refresh_token_request.freezed.dart';
|
||||
part 'refresh_token_request.g.dart';
|
||||
|
||||
@freezed
|
||||
class RefreshTokenRequest with _$RefreshTokenRequest {
|
||||
const factory RefreshTokenRequest({
|
||||
required String token,
|
||||
}) = _RefreshTokenRequest;
|
||||
|
||||
factory RefreshTokenRequest.fromJson(Map<String, dynamic> json) =>
|
||||
_$RefreshTokenRequestFromJson(json);
|
||||
}
|
166
lib/auth/client/refresh_token_request.freezed.dart
Normal file
166
lib/auth/client/refresh_token_request.freezed.dart
Normal file
@ -0,0 +1,166 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'refresh_token_request.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
RefreshTokenRequest _$RefreshTokenRequestFromJson(Map<String, dynamic> json) {
|
||||
return _RefreshTokenRequest.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$RefreshTokenRequest {
|
||||
String get token => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this RefreshTokenRequest to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of RefreshTokenRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$RefreshTokenRequestCopyWith<RefreshTokenRequest> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $RefreshTokenRequestCopyWith<$Res> {
|
||||
factory $RefreshTokenRequestCopyWith(
|
||||
RefreshTokenRequest value, $Res Function(RefreshTokenRequest) then) =
|
||||
_$RefreshTokenRequestCopyWithImpl<$Res, RefreshTokenRequest>;
|
||||
@useResult
|
||||
$Res call({String token});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$RefreshTokenRequestCopyWithImpl<$Res, $Val extends RefreshTokenRequest>
|
||||
implements $RefreshTokenRequestCopyWith<$Res> {
|
||||
_$RefreshTokenRequestCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of RefreshTokenRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? token = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
token: null == token
|
||||
? _value.token
|
||||
: token // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$RefreshTokenRequestImplCopyWith<$Res>
|
||||
implements $RefreshTokenRequestCopyWith<$Res> {
|
||||
factory _$$RefreshTokenRequestImplCopyWith(_$RefreshTokenRequestImpl value,
|
||||
$Res Function(_$RefreshTokenRequestImpl) then) =
|
||||
__$$RefreshTokenRequestImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String token});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$RefreshTokenRequestImplCopyWithImpl<$Res>
|
||||
extends _$RefreshTokenRequestCopyWithImpl<$Res, _$RefreshTokenRequestImpl>
|
||||
implements _$$RefreshTokenRequestImplCopyWith<$Res> {
|
||||
__$$RefreshTokenRequestImplCopyWithImpl(_$RefreshTokenRequestImpl _value,
|
||||
$Res Function(_$RefreshTokenRequestImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of RefreshTokenRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? token = null,
|
||||
}) {
|
||||
return _then(_$RefreshTokenRequestImpl(
|
||||
token: null == token
|
||||
? _value.token
|
||||
: token // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$RefreshTokenRequestImpl implements _RefreshTokenRequest {
|
||||
const _$RefreshTokenRequestImpl({required this.token});
|
||||
|
||||
factory _$RefreshTokenRequestImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$RefreshTokenRequestImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String token;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RefreshTokenRequest(token: $token)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$RefreshTokenRequestImpl &&
|
||||
(identical(other.token, token) || other.token == token));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, token);
|
||||
|
||||
/// Create a copy of RefreshTokenRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$RefreshTokenRequestImplCopyWith<_$RefreshTokenRequestImpl> get copyWith =>
|
||||
__$$RefreshTokenRequestImplCopyWithImpl<_$RefreshTokenRequestImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$RefreshTokenRequestImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _RefreshTokenRequest implements RefreshTokenRequest {
|
||||
const factory _RefreshTokenRequest({required final String token}) =
|
||||
_$RefreshTokenRequestImpl;
|
||||
|
||||
factory _RefreshTokenRequest.fromJson(Map<String, dynamic> json) =
|
||||
_$RefreshTokenRequestImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get token;
|
||||
|
||||
/// Create a copy of RefreshTokenRequest
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$RefreshTokenRequestImplCopyWith<_$RefreshTokenRequestImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
19
lib/auth/client/refresh_token_request.g.dart
Normal file
19
lib/auth/client/refresh_token_request.g.dart
Normal file
@ -0,0 +1,19 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'refresh_token_request.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$RefreshTokenRequestImpl _$$RefreshTokenRequestImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$RefreshTokenRequestImpl(
|
||||
token: json['token'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$RefreshTokenRequestImplToJson(
|
||||
_$RefreshTokenRequestImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'token': instance.token,
|
||||
};
|
54
lib/auth/interceptor/auth_interceptor.dart
Normal file
54
lib/auth/interceptor/auth_interceptor.dart
Normal file
@ -0,0 +1,54 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_jwt_auth/auth/state/auth_controller.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class AuthInterceptor extends Interceptor {
|
||||
final Ref ref;
|
||||
final Dio dio;
|
||||
|
||||
const AuthInterceptor(this.ref, this.dio);
|
||||
|
||||
@override
|
||||
void onRequest(
|
||||
RequestOptions options, RequestInterceptorHandler handler) async {
|
||||
final authData = await ref.read(authControllerProvider.future);
|
||||
final token = authData?.token;
|
||||
if (token != null) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
|
||||
super.onRequest(options, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) async {
|
||||
final isRetry = err.requestOptions.extra['isRetry'] == true;
|
||||
|
||||
// if response is unauthorized
|
||||
if (err.response?.statusCode == 401 && !isRetry) {
|
||||
try {
|
||||
final authData = await ref.read(authControllerProvider.future);
|
||||
final refreshToken = authData?.refreshToken;
|
||||
|
||||
if (refreshToken != null) {
|
||||
await ref.read(authControllerProvider.notifier).refreshToken();
|
||||
|
||||
final options = err.requestOptions;
|
||||
options.extra['isRetry'] = true;
|
||||
final response = await dio.fetch(options);
|
||||
|
||||
handler.resolve(response);
|
||||
} else {
|
||||
super.onError(err, handler);
|
||||
}
|
||||
} on DioException catch (error, trace) {
|
||||
log('cannot refresh', error: error, stackTrace: trace);
|
||||
super.onError(error, handler);
|
||||
}
|
||||
} else {
|
||||
super.onError(err, handler);
|
||||
}
|
||||
}
|
||||
}
|
16
lib/auth/model/auth_data.dart
Normal file
16
lib/auth/model/auth_data.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'auth_data.freezed.dart';
|
||||
part 'auth_data.g.dart';
|
||||
|
||||
@freezed
|
||||
class AuthData with _$AuthData {
|
||||
const factory AuthData({
|
||||
required String token,
|
||||
required String refreshToken,
|
||||
}) = _AuthData;
|
||||
|
||||
factory AuthData.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthDataFromJson(json);
|
||||
}
|
191
lib/auth/model/auth_data.freezed.dart
Normal file
191
lib/auth/model/auth_data.freezed.dart
Normal file
@ -0,0 +1,191 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'auth_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
AuthData _$AuthDataFromJson(Map<String, dynamic> json) {
|
||||
return _AuthData.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$AuthData {
|
||||
String get token => throw _privateConstructorUsedError;
|
||||
String get refreshToken => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this AuthData to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of AuthData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$AuthDataCopyWith<AuthData> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $AuthDataCopyWith<$Res> {
|
||||
factory $AuthDataCopyWith(AuthData value, $Res Function(AuthData) then) =
|
||||
_$AuthDataCopyWithImpl<$Res, AuthData>;
|
||||
@useResult
|
||||
$Res call({String token, String refreshToken});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AuthDataCopyWithImpl<$Res, $Val extends AuthData>
|
||||
implements $AuthDataCopyWith<$Res> {
|
||||
_$AuthDataCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of AuthData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? token = null,
|
||||
Object? refreshToken = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
token: null == token
|
||||
? _value.token
|
||||
: token // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
refreshToken: null == refreshToken
|
||||
? _value.refreshToken
|
||||
: refreshToken // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$AuthDataImplCopyWith<$Res>
|
||||
implements $AuthDataCopyWith<$Res> {
|
||||
factory _$$AuthDataImplCopyWith(
|
||||
_$AuthDataImpl value, $Res Function(_$AuthDataImpl) then) =
|
||||
__$$AuthDataImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String token, String refreshToken});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$AuthDataImplCopyWithImpl<$Res>
|
||||
extends _$AuthDataCopyWithImpl<$Res, _$AuthDataImpl>
|
||||
implements _$$AuthDataImplCopyWith<$Res> {
|
||||
__$$AuthDataImplCopyWithImpl(
|
||||
_$AuthDataImpl _value, $Res Function(_$AuthDataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of AuthData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? token = null,
|
||||
Object? refreshToken = null,
|
||||
}) {
|
||||
return _then(_$AuthDataImpl(
|
||||
token: null == token
|
||||
? _value.token
|
||||
: token // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
refreshToken: null == refreshToken
|
||||
? _value.refreshToken
|
||||
: refreshToken // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$AuthDataImpl with DiagnosticableTreeMixin implements _AuthData {
|
||||
const _$AuthDataImpl({required this.token, required this.refreshToken});
|
||||
|
||||
factory _$AuthDataImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$AuthDataImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String token;
|
||||
@override
|
||||
final String refreshToken;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'AuthData(token: $token, refreshToken: $refreshToken)';
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'AuthData'))
|
||||
..add(DiagnosticsProperty('token', token))
|
||||
..add(DiagnosticsProperty('refreshToken', refreshToken));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AuthDataImpl &&
|
||||
(identical(other.token, token) || other.token == token) &&
|
||||
(identical(other.refreshToken, refreshToken) ||
|
||||
other.refreshToken == refreshToken));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, token, refreshToken);
|
||||
|
||||
/// Create a copy of AuthData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$AuthDataImplCopyWith<_$AuthDataImpl> get copyWith =>
|
||||
__$$AuthDataImplCopyWithImpl<_$AuthDataImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$AuthDataImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _AuthData implements AuthData {
|
||||
const factory _AuthData(
|
||||
{required final String token,
|
||||
required final String refreshToken}) = _$AuthDataImpl;
|
||||
|
||||
factory _AuthData.fromJson(Map<String, dynamic> json) =
|
||||
_$AuthDataImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get token;
|
||||
@override
|
||||
String get refreshToken;
|
||||
|
||||
/// Create a copy of AuthData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$AuthDataImplCopyWith<_$AuthDataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
19
lib/auth/model/auth_data.g.dart
Normal file
19
lib/auth/model/auth_data.g.dart
Normal file
@ -0,0 +1,19 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$AuthDataImpl _$$AuthDataImplFromJson(Map<String, dynamic> json) =>
|
||||
_$AuthDataImpl(
|
||||
token: json['token'] as String,
|
||||
refreshToken: json['refreshToken'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$AuthDataImplToJson(_$AuthDataImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'token': instance.token,
|
||||
'refreshToken': instance.refreshToken,
|
||||
};
|
23
lib/auth/repository/api_auth_repository.dart
Normal file
23
lib/auth/repository/api_auth_repository.dart
Normal file
@ -0,0 +1,23 @@
|
||||
import 'package:flutter_jwt_auth/auth/client/auth_client.dart';
|
||||
import 'package:flutter_jwt_auth/auth/client/login_request.dart';
|
||||
import 'package:flutter_jwt_auth/auth/client/refresh_token_request.dart';
|
||||
import 'package:flutter_jwt_auth/auth/model/auth_data.dart';
|
||||
import 'package:flutter_jwt_auth/auth/repository/auth_repository.dart';
|
||||
|
||||
class ApiAuthRepository implements AuthRepository {
|
||||
final AuthClient authClient;
|
||||
|
||||
const ApiAuthRepository(this.authClient);
|
||||
|
||||
@override
|
||||
Future<AuthData> login(String username) {
|
||||
final request = LoginRequest(username: username);
|
||||
return authClient.login(request);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AuthData> refreshToken(String token) {
|
||||
final request = RefreshTokenRequest(token: token);
|
||||
return authClient.refresh(request);
|
||||
}
|
||||
}
|
17
lib/auth/repository/auth_repository.dart
Normal file
17
lib/auth/repository/auth_repository.dart
Normal file
@ -0,0 +1,17 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_jwt_auth/auth/client/auth_client.dart';
|
||||
import 'package:flutter_jwt_auth/auth/model/auth_data.dart';
|
||||
import 'package:flutter_jwt_auth/auth/repository/api_auth_repository.dart';
|
||||
|
||||
part 'auth_repository.g.dart';
|
||||
|
||||
@riverpod
|
||||
AuthRepository authRepository(AuthRepositoryRef ref) => ApiAuthRepository(
|
||||
ref.watch(authClientProvider),
|
||||
);
|
||||
|
||||
abstract interface class AuthRepository {
|
||||
Future<AuthData> login(String username);
|
||||
|
||||
Future<AuthData> refreshToken(String token);
|
||||
}
|
25
lib/auth/repository/auth_repository.g.dart
Normal file
25
lib/auth/repository/auth_repository.g.dart
Normal file
@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_repository.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$authRepositoryHash() => r'0eb6db9e8bb6c8d101d6d31065b02e0d53114782';
|
||||
|
||||
/// See also [authRepository].
|
||||
@ProviderFor(authRepository)
|
||||
final authRepositoryProvider = AutoDisposeProvider<AuthRepository>.internal(
|
||||
authRepository,
|
||||
name: r'authRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$authRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef AuthRepositoryRef = AutoDisposeProviderRef<AuthRepository>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
63
lib/auth/state/auth_controller.dart
Normal file
63
lib/auth/state/auth_controller.dart
Normal file
@ -0,0 +1,63 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_jwt_auth/auth/model/auth_data.dart';
|
||||
import 'package:flutter_jwt_auth/auth/repository/auth_repository.dart';
|
||||
import 'package:flutter_jwt_auth/common/repository/storage_repository.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'auth_controller.g.dart';
|
||||
|
||||
@riverpod
|
||||
class AuthController extends _$AuthController {
|
||||
@override
|
||||
Future<AuthData?> build() async {
|
||||
final storageRepository = ref.watch(storageRepositoryProvider);
|
||||
|
||||
final token = await storageRepository.getToken();
|
||||
final refreshToken = await storageRepository.getRefreshToken();
|
||||
|
||||
if (token != null && refreshToken != null) {
|
||||
return AuthData(token: token, refreshToken: refreshToken);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> login(String username) async {
|
||||
final authRepository = ref.read(authRepositoryProvider);
|
||||
final storageRepository = ref.read(storageRepositoryProvider);
|
||||
|
||||
state = await AsyncValue.guard(() async {
|
||||
final authData = await authRepository.login(username);
|
||||
await storageRepository.storeToken(authData.token);
|
||||
await storageRepository.storeRefreshToken(authData.refreshToken);
|
||||
return authData;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> refreshToken() async {
|
||||
final authRepository = ref.read(authRepositoryProvider);
|
||||
final storageRepository = ref.read(storageRepositoryProvider);
|
||||
final authData = state.valueOrNull;
|
||||
if (authData != null) {
|
||||
try {
|
||||
final newTokens =
|
||||
await authRepository.refreshToken(authData.refreshToken);
|
||||
storageRepository.storeToken(newTokens.token);
|
||||
storageRepository.storeRefreshToken(newTokens.refreshToken);
|
||||
state = AsyncData(newTokens);
|
||||
} on DioException {
|
||||
await logout();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
state = await AsyncValue.guard(() async {
|
||||
final storageRepository = ref.read(storageRepositoryProvider);
|
||||
await storageRepository.deleteToken();
|
||||
await storageRepository.deleteRefreshToken();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
26
lib/auth/state/auth_controller.g.dart
Normal file
26
lib/auth/state/auth_controller.g.dart
Normal file
@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'auth_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$authControllerHash() => r'413fe66c0b164847c772c71ea7dfd1270ffe7672';
|
||||
|
||||
/// See also [AuthController].
|
||||
@ProviderFor(AuthController)
|
||||
final authControllerProvider =
|
||||
AutoDisposeAsyncNotifierProvider<AuthController, AuthData?>.internal(
|
||||
AuthController.new,
|
||||
name: r'authControllerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$authControllerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AuthController = AutoDisposeAsyncNotifier<AuthData?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
33
lib/common/repository/secure_storage_repository.dart
Normal file
33
lib/common/repository/secure_storage_repository.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_jwt_auth/common/repository/storage_repository.dart';
|
||||
|
||||
class SecureStorageRepository implements StorageRepository {
|
||||
static const String _keyToken = 'token';
|
||||
static const String _keyRefreshToken = 'refresh_token';
|
||||
|
||||
final FlutterSecureStorage storage;
|
||||
|
||||
const SecureStorageRepository({required this.storage});
|
||||
|
||||
// Token
|
||||
@override
|
||||
Future<String?> getToken() => storage.read(key: _keyToken);
|
||||
|
||||
@override
|
||||
Future<void> storeToken(String token) =>
|
||||
storage.write(key: _keyToken, value: token);
|
||||
|
||||
@override
|
||||
Future<void> deleteToken() => storage.delete(key: _keyToken);
|
||||
|
||||
// Refresh Token
|
||||
@override
|
||||
Future<String?> getRefreshToken() => storage.read(key: _keyRefreshToken);
|
||||
|
||||
@override
|
||||
Future<void> storeRefreshToken(String token) =>
|
||||
storage.write(key: _keyRefreshToken, value: token);
|
||||
|
||||
@override
|
||||
Future<void> deleteRefreshToken() => storage.delete(key: _keyRefreshToken);
|
||||
}
|
25
lib/common/repository/storage_repository.dart
Normal file
25
lib/common/repository/storage_repository.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_jwt_auth/common/repository/secure_storage_repository.dart';
|
||||
import 'package:flutter_jwt_auth/global_providers.dart';
|
||||
|
||||
part 'storage_repository.g.dart';
|
||||
|
||||
@riverpod
|
||||
StorageRepository storageRepository(StorageRepositoryRef ref) =>
|
||||
SecureStorageRepository(
|
||||
storage: ref.watch(flutterSecureStorageProvider),
|
||||
);
|
||||
|
||||
abstract interface class StorageRepository {
|
||||
Future<void> storeToken(String token);
|
||||
|
||||
Future<void> storeRefreshToken(String token);
|
||||
|
||||
Future<String?> getToken();
|
||||
|
||||
Future<String?> getRefreshToken();
|
||||
|
||||
Future<void> deleteToken();
|
||||
|
||||
Future<void> deleteRefreshToken();
|
||||
}
|
26
lib/common/repository/storage_repository.g.dart
Normal file
26
lib/common/repository/storage_repository.g.dart
Normal file
@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'storage_repository.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$storageRepositoryHash() => r'aa1e363c047d2b2ebca478ea1408adff6b8095e6';
|
||||
|
||||
/// See also [storageRepository].
|
||||
@ProviderFor(storageRepository)
|
||||
final storageRepositoryProvider =
|
||||
AutoDisposeProvider<StorageRepository>.internal(
|
||||
storageRepository,
|
||||
name: r'storageRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$storageRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef StorageRepositoryRef = AutoDisposeProviderRef<StorageRepository>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
33
lib/common/ui/error_view.dart
Normal file
33
lib/common/ui/error_view.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ErrorView extends StatelessWidget {
|
||||
final Object? error;
|
||||
|
||||
const ErrorView({
|
||||
super.key,
|
||||
required this.error,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final error = this.error;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
'Error',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
if (error is DioException) ...[
|
||||
Text('Status Code: ${error.response?.statusCode}'),
|
||||
Text(error.response?.statusMessage ?? '')
|
||||
] else
|
||||
Text(error.toString())
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
12
lib/common/ui/loading_view.dart
Normal file
12
lib/common/ui/loading_view.dart
Normal file
@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingView extends StatelessWidget {
|
||||
const LoadingView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
}
|
26
lib/global_providers.dart
Normal file
26
lib/global_providers.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_jwt_auth/auth/interceptor/auth_interceptor.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'global_providers.g.dart';
|
||||
|
||||
@riverpod
|
||||
Dio dio(DioRef ref) {
|
||||
final dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: 'http://localhost:8080',
|
||||
contentType: Headers.jsonContentType,
|
||||
),
|
||||
);
|
||||
|
||||
dio.interceptors.add(PrettyDioLogger());
|
||||
dio.interceptors.add(AuthInterceptor(ref, dio));
|
||||
|
||||
return dio;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
FlutterSecureStorage flutterSecureStorage(FlutterSecureStorageRef ref) =>
|
||||
const FlutterSecureStorage();
|
41
lib/global_providers.g.dart
Normal file
41
lib/global_providers.g.dart
Normal file
@ -0,0 +1,41 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'global_providers.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$dioHash() => r'9347067b2b996a62b03e4531bcbd98f9fa468a91';
|
||||
|
||||
/// See also [dio].
|
||||
@ProviderFor(dio)
|
||||
final dioProvider = AutoDisposeProvider<Dio>.internal(
|
||||
dio,
|
||||
name: r'dioProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$dioHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef DioRef = AutoDisposeProviderRef<Dio>;
|
||||
String _$flutterSecureStorageHash() =>
|
||||
r'f573db2722d185024bf535e0b496b1442ddf2db7';
|
||||
|
||||
/// See also [flutterSecureStorage].
|
||||
@ProviderFor(flutterSecureStorage)
|
||||
final flutterSecureStorageProvider =
|
||||
AutoDisposeProvider<FlutterSecureStorage>.internal(
|
||||
flutterSecureStorage,
|
||||
name: r'flutterSecureStorageProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$flutterSecureStorageHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef FlutterSecureStorageRef = AutoDisposeProviderRef<FlutterSecureStorage>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
@ -1,7 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_jwt_auth/time/ui/time_page.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MainApp());
|
||||
runApp(const ProviderScope(child: MainApp()));
|
||||
}
|
||||
|
||||
class MainApp extends StatelessWidget {
|
||||
@ -10,11 +12,8 @@ class MainApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: Text('Hello World!'),
|
||||
),
|
||||
),
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: TimePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
20
lib/time/client/time_client.dart
Normal file
20
lib/time/client/time_client.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_jwt_auth/global_providers.dart';
|
||||
import 'package:flutter_jwt_auth/time/client/time_response.dart';
|
||||
|
||||
part 'time_client.g.dart';
|
||||
|
||||
@riverpod
|
||||
TimeClient timeClient(TimeClientRef ref) => TimeClient(
|
||||
ref.watch(dioProvider),
|
||||
);
|
||||
|
||||
@RestApi()
|
||||
abstract class TimeClient {
|
||||
factory TimeClient(Dio dio) = _TimeClient;
|
||||
|
||||
@GET('/time')
|
||||
Future<TimeResponse> getServerTime();
|
||||
}
|
107
lib/time/client/time_client.g.dart
Normal file
107
lib/time/client/time_client.g.dart
Normal file
@ -0,0 +1,107 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'time_client.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RetrofitGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element
|
||||
|
||||
class _TimeClient implements TimeClient {
|
||||
_TimeClient(
|
||||
this._dio, {
|
||||
this.baseUrl,
|
||||
this.errorLogger,
|
||||
});
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
String? baseUrl;
|
||||
|
||||
final ParseErrorLogger? errorLogger;
|
||||
|
||||
@override
|
||||
Future<TimeResponse> getServerTime() async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
const Map<String, dynamic>? _data = null;
|
||||
final _options = _setStreamType<TimeResponse>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/time',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
)));
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late TimeResponse _value;
|
||||
try {
|
||||
_value = TimeResponse.fromJson(_result.data!);
|
||||
} on Object catch (e, s) {
|
||||
errorLogger?.logError(e, s, _options);
|
||||
rethrow;
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
requestOptions.responseType == ResponseType.stream)) {
|
||||
if (T == String) {
|
||||
requestOptions.responseType = ResponseType.plain;
|
||||
} else {
|
||||
requestOptions.responseType = ResponseType.json;
|
||||
}
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
String _combineBaseUrls(
|
||||
String dioBaseUrl,
|
||||
String? baseUrl,
|
||||
) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty) {
|
||||
return dioBaseUrl;
|
||||
}
|
||||
|
||||
final url = Uri.parse(baseUrl);
|
||||
|
||||
if (url.isAbsolute) {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$timeClientHash() => r'6b646e6d22b33365b77143253c69787fea6889b3';
|
||||
|
||||
/// See also [timeClient].
|
||||
@ProviderFor(timeClient)
|
||||
final timeClientProvider = AutoDisposeProvider<TimeClient>.internal(
|
||||
timeClient,
|
||||
name: r'timeClientProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$timeClientHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef TimeClientRef = AutoDisposeProviderRef<TimeClient>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
15
lib/time/client/time_response.dart
Normal file
15
lib/time/client/time_response.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'time_response.freezed.dart';
|
||||
part 'time_response.g.dart';
|
||||
|
||||
@freezed
|
||||
class TimeResponse with _$TimeResponse {
|
||||
const factory TimeResponse({
|
||||
required DateTime time,
|
||||
}) = _TimeResponse;
|
||||
|
||||
factory TimeResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$TimeResponseFromJson(json);
|
||||
}
|
173
lib/time/client/time_response.freezed.dart
Normal file
173
lib/time/client/time_response.freezed.dart
Normal file
@ -0,0 +1,173 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'time_response.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
TimeResponse _$TimeResponseFromJson(Map<String, dynamic> json) {
|
||||
return _TimeResponse.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$TimeResponse {
|
||||
DateTime get time => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this TimeResponse to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of TimeResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$TimeResponseCopyWith<TimeResponse> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TimeResponseCopyWith<$Res> {
|
||||
factory $TimeResponseCopyWith(
|
||||
TimeResponse value, $Res Function(TimeResponse) then) =
|
||||
_$TimeResponseCopyWithImpl<$Res, TimeResponse>;
|
||||
@useResult
|
||||
$Res call({DateTime time});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TimeResponseCopyWithImpl<$Res, $Val extends TimeResponse>
|
||||
implements $TimeResponseCopyWith<$Res> {
|
||||
_$TimeResponseCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TimeResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? time = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
time: null == time
|
||||
? _value.time
|
||||
: time // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$TimeResponseImplCopyWith<$Res>
|
||||
implements $TimeResponseCopyWith<$Res> {
|
||||
factory _$$TimeResponseImplCopyWith(
|
||||
_$TimeResponseImpl value, $Res Function(_$TimeResponseImpl) then) =
|
||||
__$$TimeResponseImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({DateTime time});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$TimeResponseImplCopyWithImpl<$Res>
|
||||
extends _$TimeResponseCopyWithImpl<$Res, _$TimeResponseImpl>
|
||||
implements _$$TimeResponseImplCopyWith<$Res> {
|
||||
__$$TimeResponseImplCopyWithImpl(
|
||||
_$TimeResponseImpl _value, $Res Function(_$TimeResponseImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of TimeResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? time = null,
|
||||
}) {
|
||||
return _then(_$TimeResponseImpl(
|
||||
time: null == time
|
||||
? _value.time
|
||||
: time // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$TimeResponseImpl with DiagnosticableTreeMixin implements _TimeResponse {
|
||||
const _$TimeResponseImpl({required this.time});
|
||||
|
||||
factory _$TimeResponseImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$TimeResponseImplFromJson(json);
|
||||
|
||||
@override
|
||||
final DateTime time;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'TimeResponse(time: $time)';
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'TimeResponse'))
|
||||
..add(DiagnosticsProperty('time', time));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$TimeResponseImpl &&
|
||||
(identical(other.time, time) || other.time == time));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, time);
|
||||
|
||||
/// Create a copy of TimeResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$TimeResponseImplCopyWith<_$TimeResponseImpl> get copyWith =>
|
||||
__$$TimeResponseImplCopyWithImpl<_$TimeResponseImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$TimeResponseImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _TimeResponse implements TimeResponse {
|
||||
const factory _TimeResponse({required final DateTime time}) =
|
||||
_$TimeResponseImpl;
|
||||
|
||||
factory _TimeResponse.fromJson(Map<String, dynamic> json) =
|
||||
_$TimeResponseImpl.fromJson;
|
||||
|
||||
@override
|
||||
DateTime get time;
|
||||
|
||||
/// Create a copy of TimeResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$TimeResponseImplCopyWith<_$TimeResponseImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
17
lib/time/client/time_response.g.dart
Normal file
17
lib/time/client/time_response.g.dart
Normal file
@ -0,0 +1,17 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'time_response.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$TimeResponseImpl _$$TimeResponseImplFromJson(Map<String, dynamic> json) =>
|
||||
_$TimeResponseImpl(
|
||||
time: DateTime.parse(json['time'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$TimeResponseImplToJson(_$TimeResponseImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'time': instance.time.toIso8601String(),
|
||||
};
|
19
lib/time/repository/api_time_repository.dart
Normal file
19
lib/time/repository/api_time_repository.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_jwt_auth/time/client/time_client.dart';
|
||||
import 'package:flutter_jwt_auth/time/repository/time_repository.dart';
|
||||
|
||||
class ApiTimeRepository implements TimeRepository {
|
||||
final TimeClient timeClient;
|
||||
|
||||
const ApiTimeRepository(this.timeClient);
|
||||
|
||||
@override
|
||||
Future<DateTime> getServerTime() async {
|
||||
try {
|
||||
final response = await timeClient.getServerTime();
|
||||
return response.time;
|
||||
} on DioException {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
10
lib/time/repository/mock_time_repository.dart
Normal file
10
lib/time/repository/mock_time_repository.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:flutter_jwt_auth/time/repository/time_repository.dart';
|
||||
|
||||
class MockTimeRepository implements TimeRepository {
|
||||
@override
|
||||
Future<DateTime> getServerTime() async {
|
||||
// simulate api delay
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return DateTime.now();
|
||||
}
|
||||
}
|
13
lib/time/repository/time_repository.dart
Normal file
13
lib/time/repository/time_repository.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:flutter_jwt_auth/time/client/time_client.dart';
|
||||
import 'package:flutter_jwt_auth/time/repository/api_time_repository.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'time_repository.g.dart';
|
||||
|
||||
@riverpod
|
||||
TimeRepository timeRepository(TimeRepositoryRef ref) =>
|
||||
ApiTimeRepository(ref.watch(timeClientProvider));
|
||||
|
||||
abstract interface class TimeRepository {
|
||||
Future<DateTime> getServerTime();
|
||||
}
|
25
lib/time/repository/time_repository.g.dart
Normal file
25
lib/time/repository/time_repository.g.dart
Normal file
@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'time_repository.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$timeRepositoryHash() => r'cbbdb501669190c470f58ab771d36c8fb5fccdd7';
|
||||
|
||||
/// See also [timeRepository].
|
||||
@ProviderFor(timeRepository)
|
||||
final timeRepositoryProvider = AutoDisposeProvider<TimeRepository>.internal(
|
||||
timeRepository,
|
||||
name: r'timeRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$timeRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef TimeRepositoryRef = AutoDisposeProviderRef<TimeRepository>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
13
lib/time/state/time_controller.dart
Normal file
13
lib/time/state/time_controller.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_jwt_auth/time/repository/time_repository.dart';
|
||||
|
||||
part 'time_controller.g.dart';
|
||||
|
||||
@riverpod
|
||||
class TimeController extends _$TimeController {
|
||||
@override
|
||||
Future<DateTime> build() {
|
||||
final repository = ref.watch(timeRepositoryProvider);
|
||||
return repository.getServerTime();
|
||||
}
|
||||
}
|
26
lib/time/state/time_controller.g.dart
Normal file
26
lib/time/state/time_controller.g.dart
Normal file
@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'time_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$timeControllerHash() => r'f9d6f7e9fd0adcfde0b8efa7da793670b7a0ddae';
|
||||
|
||||
/// See also [TimeController].
|
||||
@ProviderFor(TimeController)
|
||||
final timeControllerProvider =
|
||||
AutoDisposeAsyncNotifierProvider<TimeController, DateTime>.internal(
|
||||
TimeController.new,
|
||||
name: r'timeControllerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$timeControllerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$TimeController = AutoDisposeAsyncNotifier<DateTime>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
29
lib/time/ui/login_button.dart
Normal file
29
lib/time/ui/login_button.dart
Normal file
@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_jwt_auth/auth/state/auth_controller.dart';
|
||||
|
||||
class LoginButton extends ConsumerWidget {
|
||||
const LoginButton({super.key});
|
||||
|
||||
_login(WidgetRef ref) {
|
||||
ref.read(authControllerProvider.notifier).login('MyUsername');
|
||||
}
|
||||
|
||||
_logout(WidgetRef ref) {
|
||||
ref.read(authControllerProvider.notifier).logout();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final authState = ref.watch(authControllerProvider);
|
||||
|
||||
final isAuthenticated = authState.valueOrNull != null;
|
||||
|
||||
return TextButton(
|
||||
onPressed: () => isAuthenticated ? _logout(ref) : _login(ref),
|
||||
child: Text(
|
||||
isAuthenticated ? 'Log out' : 'Log in',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_jwt_auth/auth/state/auth_controller.dart';
|
||||
import 'package:flutter_jwt_auth/common/ui/error_view.dart';
|
||||
import 'package:flutter_jwt_auth/common/ui/loading_view.dart';
|
||||
import 'package:flutter_jwt_auth/time/state/time_controller.dart';
|
||||
import 'package:flutter_jwt_auth/time/ui/login_button.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class TimePage extends ConsumerWidget {
|
||||
const TimePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ref.listen(authControllerProvider, (prev, state) {
|
||||
if (state.hasError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('Login error occurred'),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('JWT Auth Tutorial'),
|
||||
actions: const [
|
||||
LoginButton(),
|
||||
],
|
||||
),
|
||||
body: const Column(
|
||||
children: [
|
||||
_AuthContent(),
|
||||
_TimeContent(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AuthContent extends ConsumerWidget {
|
||||
const _AuthContent();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final authState = ref.watch(authControllerProvider);
|
||||
|
||||
return authState.when(
|
||||
data: (authData) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ListTile(
|
||||
subtitle: const Text('Token'),
|
||||
title: Text(authData?.token ?? '–'),
|
||||
),
|
||||
ListTile(
|
||||
subtitle: const Text('Refresh Token'),
|
||||
title: Text(authData?.refreshToken ?? '–'),
|
||||
),
|
||||
],
|
||||
),
|
||||
error: (error, trace) => Center(
|
||||
child: Text(error.toString()),
|
||||
),
|
||||
loading: () => const LoadingView(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TimeContent extends ConsumerWidget {
|
||||
const _TimeContent();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isAuthorized = ref.watch(authControllerProvider).valueOrNull != null;
|
||||
|
||||
if (isAuthorized) {
|
||||
final timeState = ref.watch(timeControllerProvider);
|
||||
return timeState.when(
|
||||
data: (time) => Column(
|
||||
children: [
|
||||
ListTile(
|
||||
subtitle: const Text('Current Server Time'),
|
||||
title: Text(time.toString()),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => ref.refresh(timeControllerProvider.future),
|
||||
child: const Text('Refresh'),
|
||||
),
|
||||
],
|
||||
),
|
||||
error: (error, trace) => ErrorView(error: error),
|
||||
loading: () => const LoadingView(),
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text('Unauthorized'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
581
pubspec.lock
581
pubspec.lock
@ -1,6 +1,43 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
analyzer_plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer_plugin
|
||||
sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.3"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -17,6 +54,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.12"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -25,6 +126,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
ci:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ci
|
||||
sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -33,6 +158,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -41,6 +174,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
custom_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: custom_lint
|
||||
sha256: "6e1ec47427ca968f22bce734d00028ae7084361999b41673291138945c5baca0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
custom_lint_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_builder
|
||||
sha256: ba2f90fff4eff71d202d097eb14b14f87087eaaef742e956208c0eb9d3a40a21
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
custom_lint_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_core
|
||||
sha256: "4ddbbdaa774265de44c97054dcec058a83d9081d071785ece601e348c18c267d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.5"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.7.0"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dio_web_adapter
|
||||
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -49,6 +246,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -62,11 +275,123 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.1"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
sha256: "9f3dd2ac3b6875b0fde5b04734789c3ef35ba3965c18e99dd564a7a2f8056df6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
freezed:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.7"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.1"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.8.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -99,6 +424,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -123,6 +464,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -131,11 +488,147 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pretty_dio_logger:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pretty_dio_logger
|
||||
sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
protobuf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: protobuf
|
||||
sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
retrofit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: retrofit
|
||||
sha256: "3c9885ef3dbc5dc4b3fb0a40c972ab52e4dad04d52dac9bba24dfa76cf100451"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.1"
|
||||
retrofit_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: retrofit_generator
|
||||
sha256: f20982392512587b1cce6cd34e3cf953a01a3fe8f82e4c34e10afe65e70c3556
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.2"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.1"
|
||||
riverpod_analyzer_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod_analyzer_utils
|
||||
sha256: ac28d7bc678471ec986b42d88e5a0893513382ff7542c7ac9634463b044ac72c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.4"
|
||||
riverpod_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
riverpod_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_generator
|
||||
sha256: "63311e361ffc578d655dfc31b48dfa4ed3bc76fd06f9be845e9bf97c5c11a429"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
riverpod_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_lint
|
||||
sha256: a35a92f2c2a4b7a5d95671c96c5432b42c20f26bb3e985e83d0b186471b61a85
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.13"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.28.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.4"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -144,6 +637,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sprintf
|
||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -152,6 +653,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
state_notifier:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: state_notifier
|
||||
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -160,6 +669,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -184,6 +701,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -200,6 +741,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.5.3 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
|
17
pubspec.yaml
17
pubspec.yaml
@ -1,4 +1,4 @@
|
||||
name: src
|
||||
name: flutter_jwt_auth
|
||||
description: "A new Flutter project."
|
||||
publish_to: 'none'
|
||||
version: 0.1.0
|
||||
@ -7,14 +7,29 @@ environment:
|
||||
sdk: ^3.5.3
|
||||
|
||||
dependencies:
|
||||
dio: ^5.7.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_riverpod: ^2.5.1
|
||||
flutter_secure_storage: ^4.2.1
|
||||
freezed_annotation: ^2.4.4
|
||||
json_annotation: ^4.9.0
|
||||
pretty_dio_logger: ^1.4.0
|
||||
retrofit: ^4.4.1
|
||||
riverpod_annotation: ^2.3.5
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^4.0.0
|
||||
riverpod_generator: ^2.4.3
|
||||
build_runner: ^2.4.12
|
||||
custom_lint: ^0.6.7
|
||||
riverpod_lint: ^2.3.13
|
||||
freezed: ^2.5.7
|
||||
json_serializable: ^6.8.0
|
||||
retrofit_generator: ^9.1.2
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
1
server/shelf-jwt-test-server
Submodule
1
server/shelf-jwt-test-server
Submodule
Submodule server/shelf-jwt-test-server added at f1368334e8
Reference in New Issue
Block a user