From fa5d558e975209037ed9cd05311ddf88c9519ad4 Mon Sep 17 00:00:00 2001 From: Pratik Canopas <109139581+cp-pratik-k@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:31:44 +0530 Subject: [PATCH] Set theme (#8) --- .idea/libraries/Dart_Packages.xml | 20 +- app/ios/Flutter/AppFrameworkInfo.plist | 2 +- app/ios/Podfile | 2 +- app/ios/Podfile.lock | 4 +- app/ios/Runner.xcodeproj/project.pbxproj | 6 +- app/lib/ui/app.dart | 28 +- app/lib/ui/flow/main/main_screen.dart | 10 +- .../utils/extensions/context_extensions.dart | 13 + app/pubspec.lock | 16 + data/.flutter-plugins-dependencies | 2 +- data/lib/models/media/media.dart | 19 ++ data/lib/models/media/media.freezed.dart | 275 ++++++++++++++++++ data/lib/models/media/media.g.dart | 30 ++ data/lib/services/auth_service.dart | 12 +- data/lib/services/google_photos_service.dart | 33 +++ data/pubspec.yaml | 1 + style/lib/text/app_text_style.dart | 59 ++++ style/lib/theme/app_theme_builder.dart | 51 ++++ style/lib/theme/colors.dart | 37 +++ style/lib/theme/theme.dart | 151 ++++++++++ 20 files changed, 755 insertions(+), 16 deletions(-) create mode 100644 data/lib/models/media/media.dart create mode 100644 data/lib/models/media/media.freezed.dart create mode 100644 data/lib/models/media/media.g.dart create mode 100644 data/lib/services/google_photos_service.dart create mode 100644 style/lib/text/app_text_style.dart create mode 100644 style/lib/theme/app_theme_builder.dart create mode 100644 style/lib/theme/colors.dart create mode 100644 style/lib/theme/theme.dart diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index d8a0ed1..c53f607 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -383,8 +383,8 @@ - @@ -405,8 +405,8 @@ - @@ -452,6 +452,13 @@ + + + + + + @@ -592,6 +599,13 @@ + + + + + + @@ -783,6 +797,7 @@ + @@ -802,6 +817,7 @@ + diff --git a/app/ios/Flutter/AppFrameworkInfo.plist b/app/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/app/ios/Flutter/AppFrameworkInfo.plist +++ b/app/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/app/ios/Podfile b/app/ios/Podfile index fdcc671..d97f17e 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index a9a28a7..dbde8e7 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -67,7 +67,7 @@ SPEC CHECKSUMS: firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5 FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f FirebaseCoreInternal: b444828ea7cfd594fca83046b95db98a2be4f290 - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 google_sign_in_ios: 1bfaf6607b44cd1b24c4d4bc39719870440f9ce1 GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 @@ -75,6 +75,6 @@ SPEC CHECKSUMS: GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 -PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189 +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 COCOAPODS: 1.14.3 diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj index d23556a..196edbc 100644 --- a/app/ios/Runner.xcodeproj/project.pbxproj +++ b/app/ios/Runner.xcodeproj/project.pbxproj @@ -475,7 +475,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -603,7 +603,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -652,7 +652,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/app/lib/ui/app.dart b/app/lib/ui/app.dart index 00b1626..2e54a4e 100644 --- a/app/lib/ui/app.dart +++ b/app/lib/ui/app.dart @@ -5,6 +5,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:style/theme/theme.dart'; +import 'package:style/theme/app_theme_builder.dart'; class App extends StatefulWidget { const App({super.key}); @@ -18,12 +20,30 @@ class _AppState extends State { @override void initState() { - _router = GoRouter(initialLocation: AppRoutePath.home, routes: AppRouter.routes); + _router = GoRouter( + initialLocation: AppRoutePath.home, + routes: AppRouter.routes, + ); super.initState(); } @override Widget build(BuildContext context) { + final colorScheme = + context.isDarkMode ? appColorSchemeDark : appColorSchemeLight; + return AppTheme( + colorScheme: colorScheme, + child: _buildApp( + context: context, + colorScheme: colorScheme, + ), + ); + } + + Widget _buildApp({ + required BuildContext context, + required AppColorScheme colorScheme, + }) { if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { return CupertinoApp.router( @@ -31,6 +51,9 @@ class _AppState extends State { localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, routerConfig: _router, + theme: AppThemeBuilder.cupertinoThemeFromColorScheme( + colorScheme: colorScheme, + ), ); } return MaterialApp.router( @@ -38,6 +61,9 @@ class _AppState extends State { localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, routerConfig: _router, + theme: AppThemeBuilder.materialThemeFromColorScheme( + colorScheme: colorScheme, + ), ); } } diff --git a/app/lib/ui/flow/main/main_screen.dart b/app/lib/ui/flow/main/main_screen.dart index 16305e4..96a0890 100644 --- a/app/lib/ui/flow/main/main_screen.dart +++ b/app/lib/ui/flow/main/main_screen.dart @@ -1,4 +1,6 @@ +import 'package:cloud_gallery/utils/extensions/context_extensions.dart'; import 'package:flutter/material.dart'; +import 'package:style/text/app_text_style.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -10,10 +12,12 @@ class HomeScreen extends StatefulWidget { class _MainScreenState extends State { @override Widget build(BuildContext context) { - return const Scaffold( + return Scaffold( + backgroundColor: context.colorScheme.surface, body: Center( - child: Text('Home Screen'), - ), + child: Text('Home Screen', + style: AppTextStyles.subtitle2 + .copyWith(color: context.colorScheme.textPrimary))), ); } } diff --git a/app/lib/utils/extensions/context_extensions.dart b/app/lib/utils/extensions/context_extensions.dart index 989118f..da67f3a 100644 --- a/app/lib/utils/extensions/context_extensions.dart +++ b/app/lib/utils/extensions/context_extensions.dart @@ -1,8 +1,21 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:style/theme/theme.dart'; extension BuildContextExtensions on BuildContext { AppLocalizations get l10n => AppLocalizations.of(this); + EdgeInsets get systemPadding => MediaQuery.of(this).padding; + Size get mediaQuerySize => MediaQuery.of(this).size; + + AppColorScheme get colorScheme => appColorSchemeOf(this); + + Brightness get brightness => MediaQuery.of(this).platformBrightness; + + bool get isDarkMode => brightness == Brightness.dark; + + FocusScopeNode get focusScope => FocusScope.of(this); + + bool get use24Hour => MediaQuery.of(this).alwaysUse24HourFormat; } diff --git a/app/pubspec.lock b/app/pubspec.lock index 1910b49..f7b3276 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -508,6 +508,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.1" + json_serializable: + dependency: transitive + description: + name: json_serializable + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.dev" + source: hosted + version: "6.7.1" lints: dependency: transitive description: @@ -665,6 +673,14 @@ packages: 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: diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 432e794..1de2c2d 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.21/","native_build":true,"dependencies":[]}],"macos":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+2/","dependencies":[]}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]}],"date_created":"2024-01-17 19:19:20.833539","version":"3.16.7"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.21/","native_build":true,"dependencies":[]}],"macos":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+2/","dependencies":[]}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]}],"date_created":"2024-01-23 10:35:50.290203","version":"3.16.7"} \ No newline at end of file diff --git a/data/lib/models/media/media.dart b/data/lib/models/media/media.dart new file mode 100644 index 0000000..1d2ae4e --- /dev/null +++ b/data/lib/models/media/media.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'media.freezed.dart'; +part 'media.g.dart'; + +@freezed +class Media with _$Media { + const factory Media({ + required String id, + required String name, + required String image, + required double size, + String? mimeType, + required DateTime createdTime, + DateTime? modifiedTime, + }) = _Media; + + factory Media.fromJson(Map json) => _$MediaFromJson(json); +} diff --git a/data/lib/models/media/media.freezed.dart b/data/lib/models/media/media.freezed.dart new file mode 100644 index 0000000..b91321b --- /dev/null +++ b/data/lib/models/media/media.freezed.dart @@ -0,0 +1,275 @@ +// 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 'media.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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#custom-getters-and-methods'); + +Media _$MediaFromJson(Map json) { + return _Media.fromJson(json); +} + +/// @nodoc +mixin _$Media { + String get id => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String get image => throw _privateConstructorUsedError; + double get size => throw _privateConstructorUsedError; + String? get mimeType => throw _privateConstructorUsedError; + DateTime get createdTime => throw _privateConstructorUsedError; + DateTime? get modifiedTime => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MediaCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MediaCopyWith<$Res> { + factory $MediaCopyWith(Media value, $Res Function(Media) then) = + _$MediaCopyWithImpl<$Res, Media>; + @useResult + $Res call( + {String id, + String name, + String image, + double size, + String? mimeType, + DateTime createdTime, + DateTime? modifiedTime}); +} + +/// @nodoc +class _$MediaCopyWithImpl<$Res, $Val extends Media> + implements $MediaCopyWith<$Res> { + _$MediaCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + Object? size = null, + Object? mimeType = freezed, + Object? createdTime = null, + Object? modifiedTime = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as double, + mimeType: freezed == mimeType + ? _value.mimeType + : mimeType // ignore: cast_nullable_to_non_nullable + as String?, + createdTime: null == createdTime + ? _value.createdTime + : createdTime // ignore: cast_nullable_to_non_nullable + as DateTime, + modifiedTime: freezed == modifiedTime + ? _value.modifiedTime + : modifiedTime // ignore: cast_nullable_to_non_nullable + as DateTime?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MediaImplCopyWith<$Res> implements $MediaCopyWith<$Res> { + factory _$$MediaImplCopyWith( + _$MediaImpl value, $Res Function(_$MediaImpl) then) = + __$$MediaImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + String name, + String image, + double size, + String? mimeType, + DateTime createdTime, + DateTime? modifiedTime}); +} + +/// @nodoc +class __$$MediaImplCopyWithImpl<$Res> + extends _$MediaCopyWithImpl<$Res, _$MediaImpl> + implements _$$MediaImplCopyWith<$Res> { + __$$MediaImplCopyWithImpl( + _$MediaImpl _value, $Res Function(_$MediaImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? image = null, + Object? size = null, + Object? mimeType = freezed, + Object? createdTime = null, + Object? modifiedTime = freezed, + }) { + return _then(_$MediaImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + image: null == image + ? _value.image + : image // ignore: cast_nullable_to_non_nullable + as String, + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as double, + mimeType: freezed == mimeType + ? _value.mimeType + : mimeType // ignore: cast_nullable_to_non_nullable + as String?, + createdTime: null == createdTime + ? _value.createdTime + : createdTime // ignore: cast_nullable_to_non_nullable + as DateTime, + modifiedTime: freezed == modifiedTime + ? _value.modifiedTime + : modifiedTime // ignore: cast_nullable_to_non_nullable + as DateTime?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$MediaImpl implements _Media { + const _$MediaImpl( + {required this.id, + required this.name, + required this.image, + required this.size, + this.mimeType, + required this.createdTime, + this.modifiedTime}); + + factory _$MediaImpl.fromJson(Map json) => + _$$MediaImplFromJson(json); + + @override + final String id; + @override + final String name; + @override + final String image; + @override + final double size; + @override + final String? mimeType; + @override + final DateTime createdTime; + @override + final DateTime? modifiedTime; + + @override + String toString() { + return 'Media(id: $id, name: $name, image: $image, size: $size, mimeType: $mimeType, createdTime: $createdTime, modifiedTime: $modifiedTime)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MediaImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.image, image) || other.image == image) && + (identical(other.size, size) || other.size == size) && + (identical(other.mimeType, mimeType) || + other.mimeType == mimeType) && + (identical(other.createdTime, createdTime) || + other.createdTime == createdTime) && + (identical(other.modifiedTime, modifiedTime) || + other.modifiedTime == modifiedTime)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, id, name, image, size, mimeType, createdTime, modifiedTime); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MediaImplCopyWith<_$MediaImpl> get copyWith => + __$$MediaImplCopyWithImpl<_$MediaImpl>(this, _$identity); + + @override + Map toJson() { + return _$$MediaImplToJson( + this, + ); + } +} + +abstract class _Media implements Media { + const factory _Media( + {required final String id, + required final String name, + required final String image, + required final double size, + final String? mimeType, + required final DateTime createdTime, + final DateTime? modifiedTime}) = _$MediaImpl; + + factory _Media.fromJson(Map json) = _$MediaImpl.fromJson; + + @override + String get id; + @override + String get name; + @override + String get image; + @override + double get size; + @override + String? get mimeType; + @override + DateTime get createdTime; + @override + DateTime? get modifiedTime; + @override + @JsonKey(ignore: true) + _$$MediaImplCopyWith<_$MediaImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/data/lib/models/media/media.g.dart b/data/lib/models/media/media.g.dart new file mode 100644 index 0000000..a83033e --- /dev/null +++ b/data/lib/models/media/media.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'media.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$MediaImpl _$$MediaImplFromJson(Map json) => _$MediaImpl( + id: json['id'] as String, + name: json['name'] as String, + image: json['image'] as String, + size: (json['size'] as num).toDouble(), + mimeType: json['mimeType'] as String?, + createdTime: DateTime.parse(json['createdTime'] as String), + modifiedTime: json['modifiedTime'] == null + ? null + : DateTime.parse(json['modifiedTime'] as String), + ); + +Map _$$MediaImplToJson(_$MediaImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + 'image': instance.image, + 'size': instance.size, + 'mimeType': instance.mimeType, + 'createdTime': instance.createdTime.toIso8601String(), + 'modifiedTime': instance.modifiedTime?.toIso8601String(), + }; diff --git a/data/lib/services/auth_service.dart b/data/lib/services/auth_service.dart index 6753c34..1dade3c 100644 --- a/data/lib/services/auth_service.dart +++ b/data/lib/services/auth_service.dart @@ -1,11 +1,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_sign_in/google_sign_in.dart'; -import 'package:googleapis/drive/v3.dart' as drive; +import 'package:googleapis/drive/v3.dart' as google_drive; +import 'package:googleapis/photoslibrary/v1.dart' as google_photos; final googleSignInProvider = Provider( (ref) => GoogleSignIn( scopes: [ - drive.DriveApi.driveScope, + google_drive.DriveApi.driveScope, + google_photos.PhotosLibraryApi.photoslibraryScope, ], ), ); @@ -39,4 +41,10 @@ class AuthService { rethrow; } } + + Future isSignedIn() async { + return _googleSignIn.isSignedIn(); + } + + GoogleSignInAccount? get getUser => _googleSignIn.currentUser; } diff --git a/data/lib/services/google_photos_service.dart b/data/lib/services/google_photos_service.dart new file mode 100644 index 0000000..da2b861 --- /dev/null +++ b/data/lib/services/google_photos_service.dart @@ -0,0 +1,33 @@ +import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:googleapis/photoslibrary/v1.dart' as google_photos; + +import 'auth_service.dart'; + +final googlePhotosServiceProvider = Provider( + (ref) => GooglePhotosService( + ref.read(googleSignInProvider), + ), +); + +class GooglePhotosService { + final GoogleSignIn _googleSignIn; + + const GooglePhotosService(this._googleSignIn); + + Future createAlbum() async { + if (_googleSignIn.currentUser == null) return; + final client = await _googleSignIn.authenticatedClient(); + final photosLibraryApi = google_photos.PhotosLibraryApi(client!); + final album = google_photos.Album( + title: "Cloud Gallery", + isWriteable: true, + ); + await photosLibraryApi.albums + .create(google_photos.CreateAlbumRequest(album: album)); + + ///TODO: Steps after create albums + } + +} diff --git a/data/pubspec.yaml b/data/pubspec.yaml index da6ae01..6cf3bcd 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: # ode generation freezed: ^2.4.6 freezed_annotation: ^2.4.1 + json_serializable: ^6.7.1 dev_dependencies: flutter_test: diff --git a/style/lib/text/app_text_style.dart b/style/lib/text/app_text_style.dart new file mode 100644 index 0000000..9f937a9 --- /dev/null +++ b/style/lib/text/app_text_style.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart' show TextStyle, FontWeight; + +class AppTextStyles { + static const TextStyle header1 = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 24, + ); + + static const TextStyle header2 = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 22, + ); + + static const TextStyle header3 = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 20, + ); + + static const TextStyle header4 = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 18, + ); + + static const TextStyle subtitle1 = TextStyle( + fontWeight: FontWeight.w500, + fontSize: 18, + ); + + static const TextStyle subtitle2 = TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + ); + + static const TextStyle button = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ); + + static const TextStyle bodyLarge = TextStyle( + fontSize: 17, + ); + + static const TextStyle body = TextStyle(fontSize: 16); + + static const TextStyle bodyBold = TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + ); + + static const TextStyle body2 = TextStyle( + fontWeight: FontWeight.w500, + fontSize: 14, + ); + + static const TextStyle caption = TextStyle( + fontWeight: FontWeight.w500, + fontSize: 12, + ); +} diff --git a/style/lib/theme/app_theme_builder.dart b/style/lib/theme/app_theme_builder.dart new file mode 100644 index 0000000..72fc808 --- /dev/null +++ b/style/lib/theme/app_theme_builder.dart @@ -0,0 +1,51 @@ +import 'package:flutter/cupertino.dart' + show CupertinoTextThemeData, CupertinoThemeData; +import 'package:flutter/material.dart' show AppBarTheme, ColorScheme, ThemeData; +import 'package:style/theme/theme.dart' show AppColorScheme; + +class AppThemeBuilder { + static ThemeData materialThemeFromColorScheme( + {required AppColorScheme colorScheme}) { + return ThemeData( + useMaterial3: true, + brightness: colorScheme.brightness, + primaryColor: colorScheme.primary, + dividerColor: colorScheme.outline, + colorScheme: ColorScheme( + primary: colorScheme.primary, + secondary: colorScheme.secondary, + tertiary: colorScheme.tertiary, + surface: colorScheme.surface, + onPrimary: colorScheme.onPrimary, + onSecondary: colorScheme.onSecondary, + onSurface: colorScheme.textPrimary, + outline: colorScheme.outline, + brightness: colorScheme.brightness, + error: colorScheme.alert, + onError: colorScheme.onPrimary, + background: colorScheme.surface, + onBackground: colorScheme.textPrimary, + ), + scaffoldBackgroundColor: colorScheme.surface, + appBarTheme: AppBarTheme( + backgroundColor: colorScheme.surface, + surfaceTintColor: colorScheme.containerLow, + ), + ); + } + + static CupertinoThemeData cupertinoThemeFromColorScheme( + {required AppColorScheme colorScheme}) { + return CupertinoThemeData( + brightness: colorScheme.brightness, + primaryColor: colorScheme.primary, + primaryContrastingColor: colorScheme.onPrimary, + barBackgroundColor: colorScheme.surface, + scaffoldBackgroundColor: colorScheme.surface, + textTheme: CupertinoTextThemeData( + primaryColor: colorScheme.textPrimary, + ), + applyThemeToAll: true, + ); + } +} diff --git a/style/lib/theme/colors.dart b/style/lib/theme/colors.dart new file mode 100644 index 0000000..193cab4 --- /dev/null +++ b/style/lib/theme/colors.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart' show Color; + +class AppColors { + static const primaryColor = Color(0xFFFF9800); + + static const secondaryLightColor = Color(0xFF34495E); + static const secondaryDarkColor = Color(0xFFCEE5FF); + + static const tertiaryDarkColor = Color(0xFF58633A); + static const tertiaryLightColor = Color(0xFFDCE8B4); + + static const containerHighLightColor = Color(0x2934495E); + static const containerNormalLightColor = Color(0x1434495E); + static const containerLowLightColor = Color(0x0A34495E); + + static const containerHighDarkColor = Color(0x3DCEE5FF); + static const containerNormalDarkColor = Color(0x29CEE5FF); + static const containerLowDarkColor = Color(0x14CEE5FF); + + static const surfaceLightColor = Color(0xFFFFFFFF); + static const surfaceDarkColor = Color(0xFF000000); + + static const textPrimaryLightColor = Color(0xDE000000); + static const textSecondaryLightColor = Color(0x99000000); + static const textDisabledLightColor = Color(0x66000000); + + static const textPrimaryDarkColor = Color(0xF7FFFFFF); + static const textSecondaryDarkColor = Color(0xB3FFFFFF); + static const textDisabledDarkColor = Color(0x80FFFFFF); + + static const outlineLightColor = Color(0x14000000); + static const outlineDarkColor = Color(0x14FFFFFF); + + static const awarenessAlertColor = Color(0xFFCA2F27); + static const awarenessPositiveColor = Color(0xFF47A96E); + static const awarenessWarningColor = Color(0xFFFFA500); +} diff --git a/style/lib/theme/theme.dart b/style/lib/theme/theme.dart new file mode 100644 index 0000000..2637e51 --- /dev/null +++ b/style/lib/theme/theme.dart @@ -0,0 +1,151 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'colors.dart'; + +class AppTheme extends InheritedWidget { + final AppColorScheme colorScheme; + + const AppTheme({ + super.key, + required this.colorScheme, + required super.child, + }); + + @override + bool updateShouldNotify(AppTheme oldWidget) { + return colorScheme != oldWidget.colorScheme; + } +} + +AppColorScheme appColorSchemeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType()!.colorScheme; +} + +class AppColorScheme { + final Color primary; + final Color secondary; + final Color secondaryInverse; + final Color tertiary; + final Color tertiaryInverse; + final Color surface; + final Color outline; + final Color textPrimary; + final Color textSecondary; + final Color textDisabled; + final Color outlineInverse; + final Color textInversePrimary; + final Color textInverseSecondary; + final Color textInverseDisabled; + final Color containerHighInverse; + final Color containerNormalInverse; + final Color containerLowInverse; + final Color containerHigh; + final Color containerNormal; + final Color containerLow; + final Color positive; + final Color alert; + final Color warning; + final Color onPrimary; + final Color onSecondary; + final Color onDisabled; + final Brightness brightness; + + AppColorScheme({ + required this.primary, + required this.secondary, + required this.secondaryInverse, + required this.tertiary, + required this.tertiaryInverse, + required this.surface, + required this.outline, + required this.textPrimary, + required this.textSecondary, + required this.textDisabled, + required this.outlineInverse, + required this.textInversePrimary, + required this.textInverseSecondary, + required this.textInverseDisabled, + required this.containerNormalInverse, + required this.containerHighInverse, + required this.containerLowInverse, + required this.containerHigh, + required this.containerNormal, + required this.containerLow, + required this.positive, + required this.alert, + required this.warning, + required this.onPrimary, + required this.onSecondary, + required this.onDisabled, + required this.brightness, + }); + + Color get containerNormalOnSurface => + Color.alphaBlend(containerNormal, surface); + + Color get containerHighOnSurface => Color.alphaBlend(containerHigh, surface); + + Color get containerLowOnSurface => Color.alphaBlend(containerLow, surface); +} + + + +final appColorSchemeLight = AppColorScheme( + primary: AppColors.primaryColor, + secondary: AppColors.secondaryLightColor, + secondaryInverse: AppColors.secondaryDarkColor, + tertiary: AppColors.tertiaryLightColor, + tertiaryInverse: AppColors.tertiaryDarkColor, + surface: AppColors.surfaceLightColor, + outline: AppColors.outlineLightColor, + outlineInverse: AppColors.outlineDarkColor, + textPrimary: AppColors.textPrimaryLightColor, + textSecondary: AppColors.textSecondaryLightColor, + textDisabled: AppColors.textDisabledLightColor, + textInversePrimary: AppColors.textPrimaryDarkColor, + textInverseSecondary: AppColors.textSecondaryDarkColor, + textInverseDisabled: AppColors.textDisabledDarkColor, + containerHigh: AppColors.containerHighLightColor, + containerNormal: AppColors.containerNormalLightColor, + containerLow: AppColors.containerLowLightColor, + containerHighInverse: AppColors.containerHighDarkColor, + containerNormalInverse: AppColors.containerNormalDarkColor, + containerLowInverse: AppColors.containerLowDarkColor, + positive: AppColors.awarenessPositiveColor, + alert: AppColors.awarenessAlertColor, + warning: AppColors.awarenessWarningColor, + onPrimary: AppColors.textPrimaryDarkColor, + onSecondary: AppColors.textSecondaryDarkColor, + onDisabled: AppColors.textDisabledLightColor, + brightness: Brightness.light, +); + +final appColorSchemeDark = AppColorScheme( + primary: AppColors.primaryColor, + secondary: AppColors.secondaryDarkColor, + secondaryInverse: AppColors.secondaryLightColor, + tertiary: AppColors.tertiaryDarkColor, + tertiaryInverse: AppColors.tertiaryLightColor, + surface: AppColors.surfaceDarkColor, + outline: AppColors.outlineDarkColor, + outlineInverse: AppColors.outlineLightColor, + textPrimary: AppColors.textPrimaryDarkColor, + textSecondary: AppColors.textSecondaryDarkColor, + textDisabled: AppColors.textDisabledDarkColor, + textInversePrimary: AppColors.textPrimaryLightColor, + textInverseSecondary: AppColors.textSecondaryLightColor, + textInverseDisabled: AppColors.textDisabledLightColor, + containerHighInverse: AppColors.containerHighLightColor, + containerNormalInverse: AppColors.containerNormalLightColor, + containerLowInverse: AppColors.containerLowLightColor, + containerHigh: AppColors.containerHighDarkColor, + containerNormal: AppColors.containerNormalDarkColor, + containerLow: AppColors.containerLowDarkColor, + positive: AppColors.awarenessPositiveColor, + alert: AppColors.awarenessAlertColor, + warning: AppColors.awarenessWarningColor, + onPrimary: AppColors.textPrimaryDarkColor, + onSecondary: AppColors.textSecondaryDarkColor, + onDisabled: AppColors.textDisabledDarkColor, + brightness: Brightness.dark, +);