diff --git a/android/app/build.gradle b/android/app/build.gradle index 25f49c08..439aaf15 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -13,12 +13,12 @@ if (flutterRoot == null) { def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { - flutterVersionCode = '12' + flutterVersionCode = '14' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { - flutterVersionName = '3.2.2' + flutterVersionName = '3.3.3' } def keystoreProperties = new Properties() diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f84e9522..14b58734 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + - + + + + + + + diff --git a/android/app/src/main/kotlin/com/osj/lotura/MainActivity.kt b/android/app/src/main/kotlin/com/osj/lotura/MainActivity.kt new file mode 100644 index 00000000..f55a7110 --- /dev/null +++ b/android/app/src/main/kotlin/com/osj/lotura/MainActivity.kt @@ -0,0 +1,86 @@ +package com.osj.lotura + +import android.app.PendingIntent +import android.content.Intent +import android.content.IntentFilter +import android.nfc.NdefMessage +import android.nfc.NdefRecord +import android.nfc.NfcAdapter +import android.os.Bundle +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel + +class MainActivity : FlutterActivity() { + private lateinit var nfcAdapter: NfcAdapter + private var returnData = -1 + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + nfcAdapter = NfcAdapter.getDefaultAdapter(this) + + if (intent.action == NfcAdapter.ACTION_NDEF_DISCOVERED) { + val data = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) + val message = data?.get(0) as NdefMessage + val record = message.records[0] as NdefRecord + val byteArr = record.payload + + returnData = String(byteArr).toInt() + } + } + + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, + "com.osj.lotura/nfc_info" + ).setMethodCallHandler { call, result -> + when (call.method) { + "getNFCInfo" -> { + result.success("{\"index\" : $returnData}") + returnData = -1 + } + + "nfcIsAvailable" -> { + result.success(nfcAdapter.isEnabled) + } + } + } + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + if (intent.action == NfcAdapter.ACTION_NDEF_DISCOVERED) { + val data = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) + val message = data?.get(0) as NdefMessage + val record = message.records[0] as NdefRecord + val byteArr = record.payload + + returnData = String(byteArr).toInt() + } + } + + override fun onResume() { + super.onResume() + enableNfcForegroundDispatch() + } + + override fun onPause() { + super.onPause() + disableNfcForegroundDispatch() + } + + private fun enableNfcForegroundDispatch() { + val pendingIntent = PendingIntent.getActivity( + this, 0, Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), + PendingIntent.FLAG_IMMUTABLE + ) + val intentFilters = arrayOf( + IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED), + ) + nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null) + } + + private fun disableNfcForegroundDispatch() { + nfcAdapter.disableForegroundDispatch(this) + } +} diff --git a/android/app/src/main/kotlin/com/team/osj/lotura/MainActivity.kt b/android/app/src/main/kotlin/com/team/osj/lotura/MainActivity.kt deleted file mode 100644 index 4fd84dea..00000000 --- a/android/app/src/main/kotlin/com/team/osj/lotura/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.osj.lotura - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/android/build.gradle b/android/build.gradle index 749aa704..550d2e50 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,9 +6,9 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' + classpath 'com.android.tools.build:gradle:7.4.2' // START: FlutterFire Configuration - classpath 'com.google.gms:google-services:4.3.10' + classpath 'com.google.gms:google-services:4.3.14' // END: FlutterFire Configuration classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 6f0819c7..b2e48e4a 100644 --- a/ios/Podfile +++ b/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/ios/Podfile.lock b/ios/Podfile.lock index a3e10e6a..bf56ecc9 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4,6 +4,9 @@ PODS: - Firebase/Messaging (10.18.0): - Firebase/CoreOnly - FirebaseMessaging (~> 10.18.0) + - Firebase/RemoteConfig (10.18.0): + - Firebase/CoreOnly + - FirebaseRemoteConfig (~> 10.18.0) - firebase_core (2.24.2): - Firebase/CoreOnly (= 10.18.0) - Flutter @@ -11,6 +14,12 @@ PODS: - Firebase/Messaging (= 10.18.0) - firebase_core - Flutter + - firebase_remote_config (4.3.8): + - Firebase/RemoteConfig (= 10.18.0) + - firebase_core + - Flutter + - FirebaseABTesting (10.21.0): + - FirebaseCore (~> 10.0) - FirebaseCore (10.18.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) @@ -31,6 +40,14 @@ PODS: - GoogleUtilities/Reachability (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseRemoteConfig (10.18.0): + - FirebaseABTesting (~> 10.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - FirebaseSharedSwift (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseSharedSwift (10.21.0) - Flutter (1.0.0) - flutter_local_notifications (0.0.1): - Flutter @@ -60,6 +77,8 @@ PODS: - nanopb/encode (= 2.30909.1) - nanopb/decode (2.30909.1) - nanopb/encode (2.30909.1) + - package_info_plus (0.4.5): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -70,18 +89,23 @@ PODS: DEPENDENCIES: - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - Flutter (from `Flutter`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) SPEC REPOS: trunk: - Firebase + - FirebaseABTesting - FirebaseCore - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging + - FirebaseRemoteConfig + - FirebaseSharedSwift - GoogleDataTransport - GoogleUtilities - nanopb @@ -92,10 +116,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: :path: ".symlinks/plugins/firebase_messaging/ios" + firebase_remote_config: + :path: ".symlinks/plugins/firebase_remote_config/ios" Flutter: :path: Flutter flutter_local_notifications: :path: ".symlinks/plugins/flutter_local_notifications/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" url_launcher_ios: @@ -105,19 +133,24 @@ SPEC CHECKSUMS: Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06 firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5 firebase_messaging: 90e8a6db84b6e1e876cebce4f30f01dc495e7014 + firebase_remote_config: 14ad7a3c99810d373ba1ad4a754a8cf26c91d476 + FirebaseABTesting: 40774deef367dcc7b736b6c26dd59ce0fab42f41 FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f FirebaseCoreInternal: b444828ea7cfd594fca83046b95db98a2be4f290 FirebaseInstallations: 033d199474164db20c8350736842a94fe717b960 FirebaseMessaging: 9bc34a98d2e0237e1b121915120d4d48ddcf301e - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 + FirebaseRemoteConfig: bbd42790a4e84fde6aab7eae810b608e7b5c0bf6 + FirebaseSharedSwift: 19b3f709993d6fa1d84941d41c01e3c4c11eab93 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34 nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 - url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b + url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 -PODFILE CHECKSUM: b17e1ecfe97aba85f3997d462fe23d9e4313a8d8 +PODFILE CHECKSUM: 3765b805c03121794c6d132546df9366f592bc4d COCOAPODS: 1.13.0 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3db05ae4..585950bc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -161,7 +161,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -367,7 +367,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = Z25H7B85Z8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -376,7 +376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.2.2; + MARKETING_VERSION = 3.3.3; PRODUCT_BUNDLE_IDENTIFIER = com.osj.lotura; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -507,7 +507,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = Z25H7B85Z8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -516,7 +516,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.2.2; + MARKETING_VERSION = 3.3.3; PRODUCT_BUNDLE_IDENTIFIER = com.osj.lotura; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -537,7 +537,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = Z25H7B85Z8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -546,7 +546,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.2.2; + MARKETING_VERSION = 3.3.3; PRODUCT_BUNDLE_IDENTIFIER = com.osj.lotura; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 4ba725f4..498aa0d1 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ _getToken() async => await FirebaseMessaging.instance.getToken() ?? "whatThe"; - Future> getApplyList() async { + Future> getApplyList() async { final response = await http.post(Uri.parse("$baseurl/push_list"), body: {"token": await _getToken()}); if (response.statusCode != 200) throw Exception(response.body); return (jsonDecode(response.body) as List) - .map((i) => ApplyResponse.fromJson(i)) + .map((i) => ApplyResponse.fromJson(i).toEntity()) .toList(); } @@ -31,14 +32,14 @@ class RemoteApplyDataSource { } } - Future> applyCancel( + Future> applyCancel( {required ApplyCancelRequest applyCancelRequest}) async { applyCancelRequest.token = await _getToken(); final response = await http.post(Uri.parse("$baseurl/push_cancel"), body: applyCancelRequest.toJson()); if (response.statusCode != 200) throw Exception(response.body); return (jsonDecode(response.body) as List) - .map((i) => ApplyResponse.fromJson(i)) + .map((i) => ApplyResponse.fromJson(i).toEntity()) .toList(); } } diff --git a/lib/data/data_source/laundry/remote/remote_laundry_data_source.dart b/lib/data/data_source/laundry/remote/remote_laundry_data_source.dart index 6690f56e..0a96aa57 100644 --- a/lib/data/data_source/laundry/remote/remote_laundry_data_source.dart +++ b/lib/data/data_source/laundry/remote/remote_laundry_data_source.dart @@ -1,30 +1,39 @@ import 'dart:async'; +import 'dart:convert'; -import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; import 'package:lotura/data/dto/response/laundry_response.dart'; -import 'package:socket_io_client/socket_io_client.dart' as IO; +import 'package:lotura/domain/entity/laundry_entity.dart'; +import 'package:lotura/secret.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; class RemoteLaundryDataSource { - final StreamController> _streamController; - final IO.Socket _socket; + final StreamController _streamController; RemoteLaundryDataSource( - {required StreamController> streamController, - required IO.Socket socket}) - : _streamController = streamController, - _socket = socket; + {required StreamController streamController}) + : _streamController = streamController; - Stream> get laundryList => + Stream get laundryList => _streamController.stream.asBroadcastStream(); - void init() { - _socket.onConnect((data) => debugPrint("연결 성공")); - _socket.on('update', (data) { - List laundryList = List.empty(growable: true); - laundryList = (data as List) - .map((i) => LaundryResponse.fromJson(i)) - .toList(); - _streamController.sink.add(laundryList); + void webSocketInit() async { + final channel = WebSocketChannel.connect(Uri.parse(webSocketUrl)); + await channel.ready; + channel.stream.listen((data) { + _streamController.sink.add( + LaundryResponse.fromJson(jsonDecode(data) as Map) + .toEntity()); }); } + + Future> getAllLaundryList() async { + final response = await http.get(Uri.parse("$baseurl/device_list")); + if (response.statusCode != 200) { + throw Exception(response.body); + } + return (jsonDecode(response.body) as List) + .map((i) => LaundryResponse.fromJson(i).toEntity()) + .toList(); + } } diff --git a/lib/data/dto/response/apply_response.dart b/lib/data/dto/response/apply_response.dart index bd4448da..b35704d5 100644 --- a/lib/data/dto/response/apply_response.dart +++ b/lib/data/dto/response/apply_response.dart @@ -1,3 +1,5 @@ +import 'package:lotura/domain/entity/apply_entity.dart'; + class ApplyResponse { final int deviceId; final String deviceType; @@ -10,4 +12,7 @@ class ApplyResponse { deviceType: json['device_type'], ); } + + ApplyEntity toEntity() => + ApplyEntity(deviceId: deviceId, deviceType: deviceType); } diff --git a/lib/data/dto/response/laundry_response.dart b/lib/data/dto/response/laundry_response.dart index 1c028dfa..5f48e60f 100644 --- a/lib/data/dto/response/laundry_response.dart +++ b/lib/data/dto/response/laundry_response.dart @@ -1,3 +1,5 @@ +import 'package:lotura/domain/entity/laundry_entity.dart'; + class LaundryResponse { final int id; final int state; @@ -13,4 +15,12 @@ class LaundryResponse { deviceType: json['device_type'], ); } + + LaundryEntity toEntity() { + return LaundryEntity( + id: id, + state: state, + deviceType: deviceType, + ); + } } diff --git a/lib/data/repository/apply_repository_impl.dart b/lib/data/repository/apply_repository_impl.dart index 5a244097..b681dd91 100644 --- a/lib/data/repository/apply_repository_impl.dart +++ b/lib/data/repository/apply_repository_impl.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:lotura/data/data_source/apply/remote/remote_apply_data_source.dart'; import 'package:lotura/data/dto/request/apply_cancel_request.dart'; import 'package:lotura/data/dto/request/send_fcm_info_request.dart'; -import 'package:lotura/data/dto/response/apply_response.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; import 'package:lotura/domain/repository/apply_repository.dart'; class ApplyRepositoryImpl implements ApplyRepository { @@ -13,7 +13,7 @@ class ApplyRepositoryImpl implements ApplyRepository { : _remoteApplyDataSource = remoteApplyDataSource; @override - Future> getApplyList() async => + Future> getApplyList() async => _remoteApplyDataSource.getApplyList(); @override @@ -23,7 +23,7 @@ class ApplyRepositoryImpl implements ApplyRepository { sendFCMInfoRequest: sendFCMInfoRequest); @override - Future> applyCancel( + Future> applyCancel( {required ApplyCancelRequest applyCancelRequest}) async => _remoteApplyDataSource.applyCancel( applyCancelRequest: applyCancelRequest); diff --git a/lib/data/repository/laundry_repository_impl.dart b/lib/data/repository/laundry_repository_impl.dart index 8ab0d3aa..ba13ff80 100644 --- a/lib/data/repository/laundry_repository_impl.dart +++ b/lib/data/repository/laundry_repository_impl.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:lotura/data/data_source/laundry/local/local_laundry_data_source.dart'; import 'package:lotura/data/data_source/laundry/remote/remote_laundry_data_source.dart'; -import 'package:lotura/data/dto/response/laundry_response.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; import 'package:lotura/domain/repository/laundry_repository.dart'; class LaundryRepositoryImpl implements LaundryRepository { @@ -16,11 +16,11 @@ class LaundryRepositoryImpl implements LaundryRepository { _remoteLaundryDataSource = remoteLaundryDataSource; @override - Stream> get laundryList => + Stream get laundryList => _remoteLaundryDataSource.laundryList.asBroadcastStream(); @override - void init() => _remoteLaundryDataSource.init(); + void webSocketInit() => _remoteLaundryDataSource.webSocketInit(); @override int? getValue({required String key}) => @@ -29,4 +29,8 @@ class LaundryRepositoryImpl implements LaundryRepository { @override Future setValue({required String key, required int value}) => _localLaundryDataSource.setValue(key: key, value: value); + + @override + Future> getAllLaundryList() => + _remoteLaundryDataSource.getAllLaundryList(); } diff --git a/lib/di/di.dart b/lib/di/di.dart index 0ec00076..2ae441f3 100644 --- a/lib/di/di.dart +++ b/lib/di/di.dart @@ -5,39 +5,30 @@ import 'package:hive/hive.dart'; import 'package:lotura/data/data_source/apply/remote/remote_apply_data_source.dart'; import 'package:lotura/data/data_source/laundry/local/local_laundry_data_source.dart'; import 'package:lotura/data/data_source/laundry/remote/remote_laundry_data_source.dart'; -import 'package:lotura/data/dto/response/laundry_response.dart'; import 'package:lotura/data/repository/apply_repository_impl.dart'; import 'package:lotura/data/repository/laundry_repository_impl.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; import 'package:lotura/domain/repository/apply_repository.dart'; import 'package:lotura/domain/repository/laundry_repository.dart'; import 'package:lotura/domain/use_case/apply_cancel_use_case.dart'; +import 'package:lotura/domain/use_case/get_all_laundry_list_use_case.dart'; import 'package:lotura/domain/use_case/get_apply_list_use_case.dart'; import 'package:lotura/domain/use_case/get_laundry_room_index_use_case.dart'; import 'package:lotura/domain/use_case/get_laundry_status_use_case.dart'; import 'package:lotura/domain/use_case/send_fcm_info_use_case.dart'; import 'package:lotura/domain/use_case/update_laundry_room_index_use_case.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_bloc.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_bloc.dart'; import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; -import 'package:lotura/secret.dart'; -import 'package:socket_io_client/socket_io_client.dart' as IO; Future> di() async { - IO.Socket socket = IO.io( - '$baseurl/application', - IO.OptionBuilder() - .setTransports(['websocket']) - .enableForceNewConnection() - .build()); - final box = await Hive.openBox("Lotura"); LocalLaundryDataSource localLaundryDataSource = LocalLaundryDataSource(localDatabase: box); RemoteLaundryDataSource remoteLaundryDataSource = RemoteLaundryDataSource( - streamController: StreamController>.broadcast(), - socket: socket); + streamController: StreamController.broadcast()); RemoteApplyDataSource remoteApplyDataSource = RemoteApplyDataSource(); @@ -63,6 +54,9 @@ Future> di() async { GetLaundryRoomIndexUseCase getLaundryRoomIndexUseCase = GetLaundryRoomIndexUseCase(laundryRepository: laundryRepository); + GetAllLaundryListUseCase getAllLaundryListUseCase = + GetAllLaundryListUseCase(laundryRepository: laundryRepository); + UpdateLaundryRoomIndexUseCase updateLaundryRoomIndexUseCase = UpdateLaundryRoomIndexUseCase(laundryRepository: laundryRepository); @@ -73,8 +67,9 @@ Future> di() async { applyCancelUseCase: applyCancelUseCase, sendFCMInfoUseCase: sendFCMInfoUseCase)), BlocProvider( - create: (context) => - LaundryBloc(getLaundryStatusUseCase: getLaundryStatusUseCase)), + create: (context) => LaundryBloc( + getLaundryStatusUseCase: getLaundryStatusUseCase, + getAllLaundryListUseCase: getAllLaundryListUseCase)), BlocProvider( create: (context) => RoomBloc( getLaundryRoomIndexUseCase: getLaundryRoomIndexUseCase, diff --git a/lib/domain/entity/apply_entity.dart b/lib/domain/entity/apply_entity.dart new file mode 100644 index 00000000..c71ff0e7 --- /dev/null +++ b/lib/domain/entity/apply_entity.dart @@ -0,0 +1,10 @@ +import 'package:lotura/main.dart'; + +class ApplyEntity { + final int deviceId; + final String deviceType; + final Machine machine; + + ApplyEntity({required this.deviceId, required this.deviceType}) + : machine = deviceType == "WASH" ? Machine.wash : Machine.dry; +} diff --git a/lib/domain/entity/laundry_entity.dart b/lib/domain/entity/laundry_entity.dart new file mode 100644 index 00000000..a6bd449b --- /dev/null +++ b/lib/domain/entity/laundry_entity.dart @@ -0,0 +1,14 @@ +import 'package:lotura/main.dart'; + +class LaundryEntity { + final int id; + final CurrentState state; + final Machine deviceType; + + LaundryEntity({ + required this.id, + required int state, + required String deviceType, + }) : state = CurrentState.values.elementAt(state), + deviceType = deviceType == "WASH" ? Machine.wash : Machine.dry; +} diff --git a/lib/domain/entity/room_entity.dart b/lib/domain/entity/room_entity.dart new file mode 100644 index 00000000..151a7825 --- /dev/null +++ b/lib/domain/entity/room_entity.dart @@ -0,0 +1,29 @@ +import 'package:lotura/main.dart'; + +class LaundryRoomEntity { + final RoomLocation roomLocation; + final ButtonView buttonView; + final bool isClick, isNFCShowBottomSheet, showingBottomSheet; + + const LaundryRoomEntity({ + required this.roomLocation, + required this.buttonView, + required this.isClick, + required this.isNFCShowBottomSheet, + required this.showingBottomSheet, + }); + + LaundryRoomEntity copyWith( + {RoomLocation? roomLocation, + ButtonView? buttonView, + bool? isClick, + bool? isNFCShowBottomSheet, + bool? showingBottomSheet}) { + return LaundryRoomEntity( + roomLocation: roomLocation ?? this.roomLocation, + buttonView: buttonView ?? this.buttonView, + isClick: isClick ?? this.isClick, + isNFCShowBottomSheet: isNFCShowBottomSheet ?? this.isNFCShowBottomSheet, + showingBottomSheet: showingBottomSheet ?? this.showingBottomSheet); + } +} diff --git a/lib/domain/repository/apply_repository.dart b/lib/domain/repository/apply_repository.dart index 09d28479..378494e0 100644 --- a/lib/domain/repository/apply_repository.dart +++ b/lib/domain/repository/apply_repository.dart @@ -2,13 +2,13 @@ import 'dart:async'; import 'package:lotura/data/dto/request/apply_cancel_request.dart'; import 'package:lotura/data/dto/request/send_fcm_info_request.dart'; -import 'package:lotura/data/dto/response/apply_response.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; abstract class ApplyRepository { - Future> getApplyList(); + Future> getApplyList(); Future sendFCMInfo({required SendFCMInfoRequest sendFCMInfoRequest}); - Future> applyCancel( + Future> applyCancel( {required ApplyCancelRequest applyCancelRequest}); } diff --git a/lib/domain/repository/laundry_repository.dart b/lib/domain/repository/laundry_repository.dart index 44ffac38..e4d9a2fe 100644 --- a/lib/domain/repository/laundry_repository.dart +++ b/lib/domain/repository/laundry_repository.dart @@ -1,11 +1,13 @@ import 'dart:async'; -import 'package:lotura/data/dto/response/laundry_response.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; abstract class LaundryRepository { - Stream> get laundryList; + Stream get laundryList; - void init(); + void webSocketInit(); + + Future> getAllLaundryList(); Future setValue({required String key, required int value}); diff --git a/lib/domain/use_case/apply_cancel_use_case.dart b/lib/domain/use_case/apply_cancel_use_case.dart index 6711b567..be3c40e5 100644 --- a/lib/domain/use_case/apply_cancel_use_case.dart +++ b/lib/domain/use_case/apply_cancel_use_case.dart @@ -1,5 +1,5 @@ import 'package:lotura/data/dto/request/apply_cancel_request.dart'; -import 'package:lotura/data/dto/response/apply_response.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; import 'package:lotura/domain/repository/apply_repository.dart'; class ApplyCancelUseCase { @@ -8,7 +8,7 @@ class ApplyCancelUseCase { ApplyCancelUseCase({required ApplyRepository applyRepository}) : _applyRepository = applyRepository; - Future> execute( + Future> execute( {required ApplyCancelRequest applyCancelRequest}) => _applyRepository.applyCancel(applyCancelRequest: applyCancelRequest); } diff --git a/lib/domain/use_case/get_all_laundry_list_use_case.dart b/lib/domain/use_case/get_all_laundry_list_use_case.dart new file mode 100644 index 00000000..6e09a385 --- /dev/null +++ b/lib/domain/use_case/get_all_laundry_list_use_case.dart @@ -0,0 +1,12 @@ +import 'package:lotura/domain/entity/laundry_entity.dart'; +import 'package:lotura/domain/repository/laundry_repository.dart'; + +class GetAllLaundryListUseCase { + final LaundryRepository _laundryRepository; + + GetAllLaundryListUseCase({required LaundryRepository laundryRepository}) + : _laundryRepository = laundryRepository; + + Future> execute() => + _laundryRepository.getAllLaundryList(); +} diff --git a/lib/domain/use_case/get_apply_list_use_case.dart b/lib/domain/use_case/get_apply_list_use_case.dart index 60814305..62dac1c0 100644 --- a/lib/domain/use_case/get_apply_list_use_case.dart +++ b/lib/domain/use_case/get_apply_list_use_case.dart @@ -1,4 +1,4 @@ -import 'package:lotura/data/dto/response/apply_response.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; import 'package:lotura/domain/repository/apply_repository.dart'; class GetApplyListUseCase { @@ -7,5 +7,5 @@ class GetApplyListUseCase { GetApplyListUseCase({required ApplyRepository applyRepository}) : _applyRepository = applyRepository; - Future> execute() => _applyRepository.getApplyList(); + Future> execute() => _applyRepository.getApplyList(); } diff --git a/lib/domain/use_case/get_laundry_status_use_case.dart b/lib/domain/use_case/get_laundry_status_use_case.dart index 30065265..40a0e105 100644 --- a/lib/domain/use_case/get_laundry_status_use_case.dart +++ b/lib/domain/use_case/get_laundry_status_use_case.dart @@ -1,4 +1,4 @@ -import 'package:lotura/data/dto/response/laundry_response.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; import 'package:lotura/domain/repository/laundry_repository.dart'; class GetLaundryStatusUseCase { @@ -7,10 +7,9 @@ class GetLaundryStatusUseCase { GetLaundryStatusUseCase({required LaundryRepository laundryRepository}) : _laundryRepository = laundryRepository; - Stream> get laundryList => - _laundryRepository.laundryList; + Stream get laundryList => _laundryRepository.laundryList; void execute() { - _laundryRepository.init(); + _laundryRepository.webSocketInit(); } } diff --git a/lib/domain/use_case/send_fcm_info_use_case.dart b/lib/domain/use_case/send_fcm_info_use_case.dart index ae1d1987..1f40b616 100644 --- a/lib/domain/use_case/send_fcm_info_use_case.dart +++ b/lib/domain/use_case/send_fcm_info_use_case.dart @@ -1,5 +1,5 @@ import 'package:lotura/data/dto/request/send_fcm_info_request.dart'; -import 'package:lotura/data/dto/response/apply_response.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; import 'package:lotura/domain/repository/apply_repository.dart'; class SendFCMInfoUseCase { @@ -8,7 +8,7 @@ class SendFCMInfoUseCase { SendFCMInfoUseCase({required ApplyRepository applyRepository}) : _applyRepository = applyRepository; - Future> execute( + Future> execute( {required SendFCMInfoRequest sendFCMInfoRequest}) async { await _applyRepository.sendFCMInfo(sendFCMInfoRequest: sendFCMInfoRequest); return _applyRepository.getApplyList(); diff --git a/lib/init/fcm_init.dart b/lib/init/fcm_init.dart index 656dfdf5..6cb19323 100644 --- a/lib/init/fcm_init.dart +++ b/lib/init/fcm_init.dart @@ -1,11 +1,11 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:firebase_core/firebase_core.dart'; import 'package:lotura/data/dto/request/get_apply_list_request.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_bloc.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_event.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_event.dart'; void fcmInit(BuildContext context) async { await FirebaseMessaging.instance.requestPermission( diff --git a/lib/main.dart b/lib/main.dart index a21c01ff..92c9d1e7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -8,7 +10,8 @@ import 'package:lotura/di/di.dart'; import 'package:lotura/firebase_options.dart'; import 'package:lotura/init/fcm_init.dart'; import 'package:lotura/presentation/splash_page/ui/view/splash_page.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; +import 'package:lotura/presentation/utils/lotura_icons.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -16,17 +19,23 @@ void main() async { options: DefaultFirebaseOptions.currentPlatform, ); SystemChrome.setSystemUIOverlayStyle( - SystemUiOverlayStyle(statusBarColor: OSJColors.gray100), + const SystemUiOverlayStyle(statusBarColor: LoturaColors.gray100), ); await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await Hive.initFlutter(); - runApp(MyApp(blocList: await di())); + const platformMsg = MethodChannel('com.osj.lotura/nfc_info'); + final data = await platformMsg.invokeMethod("getNFCInfo"); + runApp(MyApp( + blocList: await di(), + nfcTagData: (jsonDecode(data)['index'] as int), + )); } class MyApp extends StatelessWidget { - const MyApp({super.key, required this.blocList}); + const MyApp({super.key, required this.blocList, required this.nfcTagData}); final List blocList; + final int nfcTagData; @override Widget build(BuildContext context) { @@ -42,7 +51,7 @@ class MyApp extends StatelessWidget { highlightColor: Colors.transparent, ), debugShowCheckedModeBanner: false, - home: const SplashPage(), + home: SplashPage(nfcTagData: nfcTagData), ); }, ), @@ -50,11 +59,65 @@ class MyApp extends StatelessWidget { } } -enum Status { - available, - working, - disconnected, - breakdown, +enum CurrentState { + available( + icon: LoturaIcons.checkCircle, + color: LoturaColors.green50, + deepColor: LoturaColors.green700, + text: "사용 가능"), + working( + icon: LoturaIcons.working, + color: LoturaColors.primary50, + deepColor: LoturaColors.primary700, + text: "작동중"), + disconnected( + icon: LoturaIcons.disconnected, + color: LoturaColors.white, + deepColor: LoturaColors.black, + text: "연결 끊김"), + breakdown( + icon: LoturaIcons.cancelCircle, + color: LoturaColors.red50, + deepColor: LoturaColors.red700, + text: "고장"); + + final IconData icon; + final Color color, deepColor; + final String text; + + const CurrentState({ + required this.icon, + required this.color, + required this.deepColor, + required this.text, + }); +} + +enum Machine { + wash(text: "세탁기", icon: LoturaIcons.laundry), + dry(text: "건조기", icon: LoturaIcons.dry); + + final String text; + final IconData icon; + + const Machine({required this.text, required this.icon}); } -enum Machine { wash, dry } +enum RoomLocation { + schoolSide(roomName: "남자 학교측 세탁실"), + dormitorySide(roomName: "남자 기숙사측 세탁실"), + womanRoom(roomName: "여자 세탁실"); + + const RoomLocation({required this.roomName}); + + final String roomName; +} + +enum ButtonView { + image, + icon; + + Widget get triangle => this == ButtonView.image + ? const SizedBox.shrink() + : const Icon(LoturaIcons.triangleUp, color: Colors.grey); +} diff --git a/lib/presentation/app_update_page/ui/app_update_page.dart b/lib/presentation/app_update_page/ui/app_update_page.dart new file mode 100644 index 00000000..d1cd9fa3 --- /dev/null +++ b/lib/presentation/app_update_page/ui/app_update_page.dart @@ -0,0 +1,89 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; +import 'package:lotura/presentation/utils/osj_text_button.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AppUpdatePage extends StatelessWidget { + const AppUpdatePage({super.key}); + + @override + Widget build(BuildContext context) { + return ScreenUtilInit( + designSize: const Size(430, 932), + builder: (context, child) => MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + ), + home: Scaffold( + backgroundColor: Colors.grey[600], + body: Center( + child: Dialog( + backgroundColor: LoturaColors.white, + surfaceTintColor: LoturaColors.white, + child: Container( + padding: EdgeInsets.all(30.0.r), + height: 270.0.h, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("업데이트 안내", + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 24.0.sp)), + SizedBox(height: 10.0.h), + const Expanded( + child: Text( + "Lotura의 새로운 버전이 출시되었어요!\n지금 바로 업데이트 하러 가기 ⬇️⬇️", + style: TextStyle(fontWeight: FontWeight.w500), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + OSJTextButton( + function: () { + if (Platform.isAndroid) { + SystemNavigator.pop(); + } else { + exit(0); + } + }, + width: 130.0.w, + height: 60.0.h, + fontSize: 18.0.sp, + color: LoturaColors.gray100, + fontColor: LoturaColors.black, + text: "닫기", + radius: 8.0.r, + ), + OSJTextButton( + function: () async => await launchUrl( + Uri.parse(Platform.isAndroid + ? "https://play.google.com/store/apps/details?id=com.osj.lotura" + : "https://apps.apple.com/us/app/lotura/id6448836740"), + mode: LaunchMode.externalApplication), + width: 130.0.w, + height: 60.0.h, + fontSize: 18.0.sp, + color: LoturaColors.primary700, + fontColor: LoturaColors.white, + text: "업데이트", + radius: 8.0.r, + ), + ], + ), + ], + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/main_page/bloc/apply_bloc.dart b/lib/presentation/apply_page/bloc/apply_bloc.dart similarity index 62% rename from lib/presentation/main_page/bloc/apply_bloc.dart rename to lib/presentation/apply_page/bloc/apply_bloc.dart index 418a9d08..3f325b69 100644 --- a/lib/presentation/main_page/bloc/apply_bloc.dart +++ b/lib/presentation/apply_page/bloc/apply_bloc.dart @@ -1,11 +1,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; import 'package:lotura/domain/use_case/apply_cancel_use_case.dart'; import 'package:lotura/domain/use_case/get_apply_list_use_case.dart'; import 'package:lotura/domain/use_case/send_fcm_info_use_case.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_event.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_state.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_event.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_state.dart'; -class ApplyBloc extends Bloc { +class ApplyBloc extends Bloc>> { final GetApplyListUseCase _getApplyListUseCase; final SendFCMInfoUseCase _sendFCMInfoUseCase; final ApplyCancelUseCase _applyCancelUseCase; @@ -23,37 +24,37 @@ class ApplyBloc extends Bloc { on(_applyCancelEventHandler); } - void _getApplyListEventHandler( - GetApplyListEvent event, Emitter emit) async { + void _getApplyListEventHandler(GetApplyListEvent event, + Emitter>> emit) async { try { emit(Loading()); - emit(Loaded(applyList: await _getApplyListUseCase.execute())); + emit(Loaded(data: await _getApplyListUseCase.execute())); } catch (e) { - emit(Error(message: e.toString())); + emit(Error(errorMessage: e)); } } void _sendFCMEventHandler( - SendFCMEvent event, Emitter emit) async { + SendFCMEvent event, Emitter>> emit) async { try { emit(Loading()); final applyList = await _sendFCMInfoUseCase.execute( sendFCMInfoRequest: event.sendFCMInfoRequest); - emit(Loaded(applyList: applyList)); + emit(Loaded(data: applyList)); } catch (e) { - emit(Error(message: e.toString())); + emit(Error(errorMessage: e)); } } - void _applyCancelEventHandler( - ApplyCancelEvent event, Emitter emit) async { + void _applyCancelEventHandler(ApplyCancelEvent event, + Emitter>> emit) async { try { emit(Loading()); final applyList = await _applyCancelUseCase.execute( applyCancelRequest: event.applyCancelRequest); - emit(Loaded(applyList: applyList)); + emit(Loaded(data: applyList)); } catch (e) { - emit(Error(message: e.toString())); + emit(Error(errorMessage: e)); } } } diff --git a/lib/presentation/main_page/bloc/apply_event.dart b/lib/presentation/apply_page/bloc/apply_event.dart similarity index 71% rename from lib/presentation/main_page/bloc/apply_event.dart rename to lib/presentation/apply_page/bloc/apply_event.dart index 8e3af381..2fd01b90 100644 --- a/lib/presentation/main_page/bloc/apply_event.dart +++ b/lib/presentation/apply_page/bloc/apply_event.dart @@ -1,33 +1,23 @@ -import 'package:equatable/equatable.dart'; import 'package:lotura/data/dto/request/apply_cancel_request.dart'; import 'package:lotura/data/dto/request/get_apply_list_request.dart'; import 'package:lotura/data/dto/request/send_fcm_info_request.dart'; -abstract class ApplyEvent extends Equatable {} +abstract class ApplyEvent {} class GetApplyListEvent extends ApplyEvent { final GetApplyListRequest getApplyListRequest; GetApplyListEvent({required this.getApplyListRequest}); - - @override - List get props => []; } class ApplyCancelEvent extends ApplyEvent { final ApplyCancelRequest applyCancelRequest; ApplyCancelEvent({required this.applyCancelRequest}); - - @override - List get props => [applyCancelRequest]; } class SendFCMEvent extends ApplyEvent { final SendFCMInfoRequest sendFCMInfoRequest; SendFCMEvent({required this.sendFCMInfoRequest}); - - @override - List get props => [sendFCMInfoRequest]; } diff --git a/lib/presentation/apply_page/bloc/apply_state.dart b/lib/presentation/apply_page/bloc/apply_state.dart new file mode 100644 index 00000000..2d4d64e9 --- /dev/null +++ b/lib/presentation/apply_page/bloc/apply_state.dart @@ -0,0 +1,33 @@ +enum ApplyStateEnum { empty, loading, error, loaded } + +sealed class ApplyState { + ApplyState({required this.applyStateEnum, this.error, this.valueOrNull}); + + T? valueOrNull; + Object? error; + ApplyStateEnum applyStateEnum; + + T get value => valueOrNull!; +} + +class Empty extends ApplyState { + Empty() : super(applyStateEnum: ApplyStateEnum.empty); +} + +class Loading extends ApplyState { + Loading() : super(applyStateEnum: ApplyStateEnum.loading); +} + +class Error extends ApplyState { + final Object errorMessage; + + Error({required this.errorMessage}) + : super(applyStateEnum: ApplyStateEnum.error, error: errorMessage); +} + +class Loaded extends ApplyState { + final T data; + + Loaded({required this.data}) + : super(applyStateEnum: ApplyStateEnum.loaded, valueOrNull: data); +} diff --git a/lib/presentation/apply_page/ui/view/apply_page.dart b/lib/presentation/apply_page/ui/view/apply_page.dart new file mode 100644 index 00000000..8eacaa87 --- /dev/null +++ b/lib/presentation/apply_page/ui/view/apply_page.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:lotura/domain/entity/apply_entity.dart'; +import 'package:lotura/main.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_state.dart'; +import 'package:lotura/presentation/setting_page/ui/view/setting_page.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; +import 'package:lotura/presentation/utils/machine_card.dart'; + +class ApplyPage extends StatelessWidget { + ApplyPage({super.key}); + + final TextStyle bigStyle = TextStyle( + fontSize: 40.0.sp, + color: LoturaColors.black, + fontWeight: FontWeight.bold, + ); + + final TextStyle smallStyle = TextStyle( + fontSize: 16.0.sp, + color: LoturaColors.gray500, + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: LoturaColors.gray100, + appBar: AppBar( + backgroundColor: LoturaColors.gray100, + elevation: 0.0, + leadingWidth: 200.0.w, + leading: Row( + children: [ + SizedBox(width: 24.0.w), + Image.asset( + "assets/applogo.jpeg", + width: 24.0.w, + height: 24.0.h, + ), + SizedBox(width: 8.0.w), + Text( + "OSJ", + style: TextStyle( + fontSize: 20.0.sp, + color: LoturaColors.primary700, + fontWeight: FontWeight.bold), + ), + ], + ), + actions: [ + IconButton( + onPressed: () => Navigator.push(context, + MaterialPageRoute(builder: (context) => const SettingPage())), + icon: const Icon( + Icons.settings, + color: LoturaColors.black, + )), + SizedBox(width: 24.0.w), + ], + ), + body: Padding( + padding: EdgeInsets.only(left: 24.0.w, right: 24.0.w, top: 36.0.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("알림 설정한", style: bigStyle), + Text("세탁기와 건조기", style: bigStyle), + SizedBox(height: 24.0.h), + Text("알림을 설정하여 세탁기와 건조기를", style: smallStyle), + SizedBox(height: 5.0.h), + Text("누구보다 빠르게 사용해보세요.", style: smallStyle), + ], + ), + SizedBox(height: 20.0.h), + Expanded( + child: BlocBuilder>>( + builder: (context, state) { + return switch (state) { + Empty() => const Center(child: Text("비어있음")), + Loading() => + const Center(child: CircularProgressIndicator()), + Error() => Center(child: Text(state.error.toString())), + Loaded() => ScrollConfiguration( + behavior: + const ScrollBehavior().copyWith(overscroll: false), + child: ListView.builder( + itemCount: state.value.length.isEven + ? state.value.length ~/ 2 + : state.value.length ~/ 2 + 1, + itemBuilder: (context, index) { + return Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + MachineCard( + index: state.value[index * 2].deviceId, + isEnableNotification: false, + isWoman: + state.value[index * 2].deviceId > 31 + ? true + : false, + machine: state.value[index * 2].machine, + state: CurrentState.working), + index * 2 + 1 < state.value.length + ? MachineCard( + index: state + .value[index * 2 + 1].deviceId, + isEnableNotification: false, + isWoman: state.value[index * 2 + 1] + .deviceId > + 31 + ? true + : false, + machine: state + .value[index * 2 + 1].machine, + state: CurrentState.working) + : SizedBox( + width: 185.0.w, + height: 256.0.h, + ), + ], + ), + SizedBox(height: 10.0.h), + ], + ); + }, + ), + ), + }; + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/laundry_room_page/bloc/laundry_bloc.dart b/lib/presentation/laundry_room_page/bloc/laundry_bloc.dart index 859464dc..6da2b012 100644 --- a/lib/presentation/laundry_room_page/bloc/laundry_bloc.dart +++ b/lib/presentation/laundry_room_page/bloc/laundry_bloc.dart @@ -1,27 +1,55 @@ import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; +import 'package:lotura/domain/use_case/get_all_laundry_list_use_case.dart'; import 'package:lotura/domain/use_case/get_laundry_status_use_case.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_event.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_state.dart'; -class LaundryBloc extends Bloc { +class LaundryBloc + extends Bloc>> { final GetLaundryStatusUseCase _getLaundryStatusUseCase; + final GetAllLaundryListUseCase _getAllLaundryListEventUseCase; - LaundryBloc({required GetLaundryStatusUseCase getLaundryStatusUseCase}) + LaundryBloc( + {required GetLaundryStatusUseCase getLaundryStatusUseCase, + required GetAllLaundryListUseCase getAllLaundryListUseCase}) : _getLaundryStatusUseCase = getLaundryStatusUseCase, + _getAllLaundryListEventUseCase = getAllLaundryListUseCase, super(Empty()) { on(_getLaundryEventHandler); + on(_getAllLaundryListEventHandler); } - void _getLaundryEventHandler( - GetLaundryEvent event, Emitter emit) async { + void _getLaundryEventHandler(GetLaundryEvent event, + Emitter>> emit) async { try { _getLaundryStatusUseCase.execute(); - emit(Loading()); - await for (var value in _getLaundryStatusUseCase.laundryList) { - emit(Loaded(laundryResponseList: value)); + await for (var data in _getLaundryStatusUseCase.laundryList) { + final newState = Loaded( + data: state.value + .map((e) => e.id == data.id + ? LaundryEntity( + id: data.id, + state: data.state.index, + deviceType: data.deviceType.name.toUpperCase()) + : e) + .toList()); + emit(newState); } } catch (e) { - emit(Error(message: e.toString())); + emit(Error(error: e)); + } + } + + void _getAllLaundryListEventHandler(GetAllLaundryListEvent event, + Emitter>> emit) async { + try { + emit(Loading()); + final newState = + Loaded(data: await _getAllLaundryListEventUseCase.execute()); + emit(newState); + } catch (e) { + emit(Error(error: e)); } } } diff --git a/lib/presentation/laundry_room_page/bloc/laundry_event.dart b/lib/presentation/laundry_room_page/bloc/laundry_event.dart index a7f44b19..70b4ac12 100644 --- a/lib/presentation/laundry_room_page/bloc/laundry_event.dart +++ b/lib/presentation/laundry_room_page/bloc/laundry_event.dart @@ -1,8 +1,5 @@ -import 'package:equatable/equatable.dart'; +abstract class LaundryEvent {} -abstract class LaundryEvent extends Equatable {} +class GetLaundryEvent extends LaundryEvent {} -class GetLaundryEvent extends LaundryEvent { - @override - List get props => []; -} +class GetAllLaundryListEvent extends LaundryEvent {} diff --git a/lib/presentation/laundry_room_page/bloc/laundry_state.dart b/lib/presentation/laundry_room_page/bloc/laundry_state.dart index 8b80f4e9..51c7f8c8 100644 --- a/lib/presentation/laundry_room_page/bloc/laundry_state.dart +++ b/lib/presentation/laundry_room_page/bloc/laundry_state.dart @@ -1,36 +1,33 @@ -import 'package:equatable/equatable.dart'; -import 'package:lotura/data/dto/response/laundry_response.dart'; +enum LaundryStateEnum { empty, loading, error, loaded } -abstract class LaundryState extends Equatable {} +sealed class LaundryState { + LaundryState({required this.laundryState, this.error, this.valueOrNull}); -class Empty extends LaundryState { - @override - List get props => []; + T? valueOrNull; + Object? error; + LaundryStateEnum laundryState; + + T get value => valueOrNull!; } -class Loading extends LaundryState { - @override - List get props => []; +class Empty extends LaundryState { + Empty() : super(laundryState: LaundryStateEnum.empty); } -class Error extends LaundryState { - final String message; +class Loading extends LaundryState { + Loading() : super(laundryState: LaundryStateEnum.loading); +} - Error({ - required this.message, - }); +class Error extends LaundryState { + final Object error; - @override - List get props => [message]; + Error({required this.error}) + : super(laundryState: LaundryStateEnum.error, error: error); } -class Loaded extends LaundryState { - final List laundryResponseList; - - Loaded({ - required this.laundryResponseList, - }); +class Loaded extends LaundryState { + final T data; - @override - List get props => [laundryResponseList]; + Loaded({required this.data}) + : super(laundryState: LaundryStateEnum.loaded, valueOrNull: data); } diff --git a/lib/presentation/laundry_room_page/ui/view/laundry_room_page.dart b/lib/presentation/laundry_room_page/ui/view/laundry_room_page.dart index cfe2ce29..58901bf5 100644 --- a/lib/presentation/laundry_room_page/ui/view/laundry_room_page.dart +++ b/lib/presentation/laundry_room_page/ui/view/laundry_room_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:lotura/domain/entity/laundry_entity.dart'; +import 'package:lotura/domain/entity/room_entity.dart'; import 'package:lotura/main.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_bloc.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_state.dart'; @@ -8,22 +10,18 @@ import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; import 'package:lotura/presentation/setting_page/bloc/room_state.dart'; import 'package:lotura/presentation/setting_page/ui/view/setting_page.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; import 'package:lotura/presentation/utils/lotura_icons.dart'; import 'package:lotura/presentation/utils/machine_button.dart'; import 'package:lotura/presentation/utils/machine_card.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/machine_widget.dart'; +import 'package:lotura/presentation/utils/osj_bottom_sheet.dart'; import 'package:lotura/presentation/utils/osj_text_button.dart'; -class LaundryRoomPage extends StatefulWidget { - const LaundryRoomPage({super.key}); +class LaundryRoomPage extends StatelessWidget { + LaundryRoomPage({super.key, required this.nfcTagData}); - @override - State createState() => _LaundryRoomPageState(); -} - -class _LaundryRoomPageState extends State { - int isSelectedIcon = 1, isSelectedPlace = 0; - bool isClick = false; + final int nfcTagData; final Map place = { 0: "남자 학교측 세탁실", @@ -31,70 +29,26 @@ class _LaundryRoomPageState extends State { 2: "여자 세탁실", }; - final Map placeIndex = {0: 0, 1: 16, 2: 31}; - - final Map status = { - 0: Status.working, - 1: Status.available, - 2: Status.disconnected, - 3: Status.breakdown - }; - - final Map machine = { - "WASH": Machine.wash, - "DRY": Machine.dry - }; - - Widget get triangle => isSelectedIcon == 0 - ? const SizedBox.shrink() - : const Icon(LoturaIcons.triangleUp, color: Colors.grey); - - Widget machineWidget( - {required int index, - required Status status, - required Machine machine}) => - isSelectedIcon == 0 - ? MachineCard( - index: index, - isEnableNotification: true, - isWoman: isSelectedPlace == 2 ? true : false, - status: status, - machine: machine) - : MachineButton( - index: index, - isEnableNotification: true, - isWoman: isSelectedPlace == 2 ? true : false, - status: status, - machine: machine); - - @override - void initState() { - super.initState(); - context.read().add(GetRoomIndexEvent()); - } + final Map placeIndex = {0: 0, 1: 16, 2: 31}; @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocBuilder>( builder: (context, roomBlocState) { if (roomBlocState is Changed) { - if (!isClick) { - isSelectedPlace = roomBlocState.index; - isClick = true; - } return Scaffold( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, appBar: AppBar( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, elevation: 0.0, leadingWidth: 300.0.w, leading: Row( children: [ SizedBox(width: 24.0.w), Text( - place[isSelectedPlace], + roomBlocState.value.roomLocation.roomName, style: TextStyle( - color: OSJColors.black, + color: LoturaColors.black, fontSize: 24.0.sp, fontWeight: FontWeight.w600, ), @@ -103,12 +57,11 @@ class _LaundryRoomPageState extends State { ), actions: [ IconButton( - onPressed: () => Navigator.push(context, - MaterialPageRoute(builder: (context) { - context.read().add(GetRoomIndexEvent()); - return const SettingPage(); - })), - icon: Icon(Icons.settings, color: OSJColors.black), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SettingPage())), + icon: Icon(Icons.settings, color: LoturaColors.black), ), SizedBox(width: 24.0.w), ], @@ -125,46 +78,58 @@ class _LaundryRoomPageState extends State { child: Row( children: [ OSJTextButton( - function: () => setState(() => isSelectedPlace = 0), + function: () => context.read().add( + ModifyRoomIndexEvent( + roomLocation: RoomLocation.schoolSide)), width: 99.0.w, height: 32.0.h, fontSize: 16.0.sp, - color: isSelectedPlace == 0 - ? OSJColors.white - : OSJColors.gray100, - fontColor: isSelectedPlace == 0 - ? OSJColors.primary700 - : OSJColors.gray300, + color: roomBlocState.value.roomLocation == + RoomLocation.schoolSide + ? LoturaColors.white + : LoturaColors.gray100, + fontColor: roomBlocState.value.roomLocation == + RoomLocation.schoolSide + ? LoturaColors.primary700 + : LoturaColors.gray300, text: "남자 학교측", radius: 8.0, ), SizedBox(width: 8.0.w), OSJTextButton( - function: () => setState(() => isSelectedPlace = 1), + function: () => context.read().add( + ModifyRoomIndexEvent( + roomLocation: RoomLocation.dormitorySide)), width: 111.0.w, height: 32.0.h, fontSize: 16.0.sp, - color: isSelectedPlace == 1 - ? OSJColors.white - : OSJColors.gray100, - fontColor: isSelectedPlace == 1 - ? OSJColors.primary700 - : OSJColors.gray300, + color: roomBlocState.value.roomLocation == + RoomLocation.dormitorySide + ? LoturaColors.white + : LoturaColors.gray100, + fontColor: roomBlocState.value.roomLocation == + RoomLocation.dormitorySide + ? LoturaColors.primary700 + : LoturaColors.gray300, text: "남자 기숙사측", radius: 8.0, ), SizedBox(width: 8.0.w), OSJTextButton( - function: () => setState(() => isSelectedPlace = 2), + function: () => context.read().add( + ModifyRoomIndexEvent( + roomLocation: RoomLocation.womanRoom)), width: 53.0.w, height: 32.0.h, fontSize: 16.0.sp, - color: isSelectedPlace == 2 - ? OSJColors.white - : OSJColors.gray100, - fontColor: isSelectedPlace == 2 - ? OSJColors.primary700 - : OSJColors.gray300, + color: roomBlocState.value.roomLocation == + RoomLocation.womanRoom + ? LoturaColors.white + : LoturaColors.gray100, + fontColor: roomBlocState.value.roomLocation == + RoomLocation.womanRoom + ? LoturaColors.primary700 + : LoturaColors.gray300, text: "여자", radius: 8.0, ), @@ -175,134 +140,46 @@ class _LaundryRoomPageState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( - onPressed: () { - setState(() { - isSelectedIcon = 0; - }); - }, + onPressed: () => context.read().add( + ModifyButtonViewEvent( + buttonView: ButtonView.image)), icon: Icon(LoturaIcons.grid, size: 18.0.r, - color: isSelectedIcon == 0 - ? OSJColors.black - : OSJColors.gray300), + color: roomBlocState.value.buttonView == + ButtonView.image + ? LoturaColors.black + : LoturaColors.gray300), ), IconButton( - onPressed: () { - setState(() { - isSelectedIcon = 1; - }); - }, + onPressed: () => context.read().add( + ModifyButtonViewEvent( + buttonView: ButtonView.icon)), icon: Icon( LoturaIcons.list, size: 18.0.r, - color: isSelectedIcon == 1 - ? OSJColors.black - : OSJColors.gray300, + color: roomBlocState.value.buttonView == + ButtonView.icon + ? LoturaColors.black + : LoturaColors.gray300, )), ], ), Expanded( - child: BlocBuilder( + child: BlocBuilder>>( builder: (context, state) { - if (state is Empty) { - return const Center(child: Text("비어있음")); - } else if (state is Loading) { - return const Center( - child: CircularProgressIndicator()); - } else if (state is Error) { - return Center(child: Text(state.message)); - } else if (state is Loaded) { - return ScrollConfiguration( - behavior: const ScrollBehavior() - .copyWith(overscroll: false), - child: ListView.builder( - itemCount: isSelectedPlace == 2 ? 10 : 8, - itemBuilder: (context, index) { - return Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - machineWidget( - index: state - .laundryResponseList[placeIndex[ - isSelectedPlace] + - index] - .id, - machine: machine[state - .laundryResponseList[placeIndex[ - isSelectedPlace] + - index] - .deviceType], - status: status[state - .laundryResponseList[placeIndex[ - isSelectedPlace] + - index] - .state]), - triangle, - machineWidget( - index: placeIndex[isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8) < - 44 - ? state - .laundryResponseList[ - placeIndex[ - isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8)] - .id - : -1, - machine: placeIndex[isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8) < - 44 - ? machine[state - .laundryResponseList[ - placeIndex[ - isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8)] - .deviceType] - : Machine.dry, - status: placeIndex[isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8) < - 44 - ? status[state - .laundryResponseList[ - placeIndex[ - isSelectedPlace] + - index + - (isSelectedPlace == 2 - ? 10 - : 8)] - .state] - : Status.breakdown, - ), - ], - ), - SizedBox(height: 10.0.h), - ], - ); - }, + return switch (state) { + Empty() => const Center(child: Text("비어있음")), + Loading() => + const Center(child: CircularProgressIndicator()), + Error() => + Center(child: Text(state.error.toString())), + Loaded() => LaundryList( + list: state.data, + roomEntity: roomBlocState.value, + nfcData: nfcTagData, ), - ); - } else { - return const Center( - child: CircularProgressIndicator()); - } + }; }, ), ), @@ -317,3 +194,145 @@ class _LaundryRoomPageState extends State { ); } } + +class LaundryList extends StatelessWidget { + LaundryList({ + super.key, + required this.list, + required this.roomEntity, + required this.nfcData, + }); + + final List list; + final LaundryRoomEntity roomEntity; + final int nfcData; + + final Map placeIndex = {0: 0, 1: 16, 2: 31}; + + MachineWidget machineWidget( + {required LaundryRoomEntity roomState, + required int index, + required CurrentState state, + required Machine machine}) => + roomState.buttonView == ButtonView.image + ? MachineCard( + index: index, + isEnableNotification: true, + isWoman: roomState.roomLocation == RoomLocation.womanRoom, + state: state, + machine: machine) + : MachineButton( + index: index, + isEnableNotification: true, + isWoman: roomState.roomLocation == RoomLocation.womanRoom, + state: state, + machine: machine); + + @override + Widget build(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback( + (_) { + if (nfcData != -1 && roomEntity.isNFCShowBottomSheet == false) { + if (roomEntity.showingBottomSheet == true) { + Navigator.of(context).pop(); + } + context.read().add(ShowBottomSheetEvent()); + context.read().add(ShowingBottomSheetEvent()); + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(25.r), + ), + ), + builder: (context) => OSJBottomSheet( + index: nfcData, + isEnableNotification: true, + isWoman: nfcData > 31 ? true : false, + state: list[nfcData - 1].state, + machine: list[nfcData - 1].deviceType, + ), + ); + } + }, + ); + return ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(overscroll: false), + child: ListView.builder( + itemCount: roomEntity.roomLocation == RoomLocation.womanRoom ? 10 : 8, + itemBuilder: (context, index) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + machineWidget( + roomState: roomEntity, + index: list[placeIndex[roomEntity.roomLocation.index]! + + index] + .id, + machine: list[placeIndex[roomEntity.roomLocation.index]! + + index] + .deviceType, + state: list[placeIndex[roomEntity.roomLocation.index]! + + index] + .state), + roomEntity.buttonView.triangle, + machineWidget( + roomState: roomEntity, + index: placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8) < + 44 + ? list[placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8)] + .id + : -1, + machine: placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8) < + 44 + ? list[placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8)] + .deviceType + : Machine.dry, + state: placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8) < + 44 + ? list[placeIndex[roomEntity.roomLocation.index]! + + index + + (roomEntity.roomLocation == + RoomLocation.womanRoom + ? 10 + : 8)] + .state + : CurrentState.breakdown, + ), + ], + ), + SizedBox(height: 10.0.h), + ], + ); + }, + ), + ); + } +} diff --git a/lib/presentation/main_page/bloc/apply_state.dart b/lib/presentation/main_page/bloc/apply_state.dart deleted file mode 100644 index 3e684633..00000000 --- a/lib/presentation/main_page/bloc/apply_state.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:lotura/data/dto/response/apply_response.dart'; - -abstract class ApplyState extends Equatable {} - -class Empty extends ApplyState { - @override - List get props => []; -} - -class Loading extends ApplyState { - @override - List get props => []; -} - -class Error extends ApplyState { - final String message; - - Error({ - required this.message, - }); - - @override - List get props => [message]; -} - -class Loaded extends ApplyState { - final List applyList; - - Loaded({ - required this.applyList, - }); - - @override - List get props => [applyList]; -} diff --git a/lib/presentation/main_page/ui/view/main_page.dart b/lib/presentation/main_page/ui/view/main_page.dart deleted file mode 100644 index 799095c2..00000000 --- a/lib/presentation/main_page/ui/view/main_page.dart +++ /dev/null @@ -1,192 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:lotura/data/dto/request/get_apply_list_request.dart'; -import 'package:lotura/main.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_bloc.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_event.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_state.dart'; -import 'package:lotura/presentation/setting_page/ui/view/setting_page.dart'; -import 'package:lotura/presentation/utils/machine_card.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; - -class MainPage extends StatefulWidget { - const MainPage({super.key}); - - @override - State createState() => _MainPageState(); -} - -class _MainPageState extends State with WidgetsBindingObserver { - int selectedIndex = 0; - - final TextStyle bigStyle = TextStyle( - fontSize: 40.0.sp, - color: OSJColors.black, - fontWeight: FontWeight.bold, - ); - - final TextStyle smallStyle = TextStyle( - fontSize: 16.0.sp, - color: OSJColors.gray500, - ); - - final Map machine = { - "WASH": Machine.wash, - "DRY": Machine.dry, - }; - - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addObserver(this); - } - - @override - void dispose() { - super.dispose(); - WidgetsBinding.instance.removeObserver(this); - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - switch (state) { - case AppLifecycleState.resumed: - BlocProvider.of(context) - .add(GetApplyListEvent(getApplyListRequest: GetApplyListRequest())); - break; - default: - break; - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: OSJColors.gray100, - appBar: AppBar( - backgroundColor: OSJColors.gray100, - elevation: 0.0, - leadingWidth: 200.0.w, - leading: Row( - children: [ - SizedBox(width: 24.0.w), - Image.asset( - "assets/applogo.jpeg", - width: 24.0.w, - height: 24.0.h, - ), - SizedBox(width: 8.0.w), - Text( - "OSJ", - style: TextStyle( - fontSize: 20.0.sp, - color: OSJColors.primary700, - fontWeight: FontWeight.bold), - ), - ], - ), - actions: [ - IconButton( - onPressed: () => Navigator.push(context, - MaterialPageRoute(builder: (context) => SettingPage())), - icon: Icon( - Icons.settings, - color: OSJColors.black, - )), - SizedBox(width: 24.0.w), - ], - ), - body: Padding( - padding: EdgeInsets.only(left: 24.0.w, right: 24.0.w, top: 36.0.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("알림 설정한", style: bigStyle), - Text("세탁기와 건조기", style: bigStyle), - SizedBox(height: 24.0.h), - Text("알림을 설정하여 세탁기와 건조기를", style: smallStyle), - SizedBox(height: 5.0.h), - Text("누구보다 빠르게 사용해보세요.", style: smallStyle), - ], - ), - SizedBox(height: 20.0.h), - Expanded( - child: BlocBuilder( - builder: (context, state) { - if (state is Empty) { - return const Center(child: Text("비어있음")); - } else if (state is Loading) { - return const Center(child: CircularProgressIndicator()); - } else if (state is Error) { - return Center(child: Text(state.message)); - } else if (state is Loaded) { - return ScrollConfiguration( - behavior: - const ScrollBehavior().copyWith(overscroll: false), - child: ListView.builder( - itemCount: state.applyList.length.isEven - ? state.applyList.length ~/ 2 - : state.applyList.length ~/ 2 + 1, - itemBuilder: (context, index) { - return Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - MachineCard( - index: - state.applyList[index * 2].deviceId, - isEnableNotification: false, - isWoman: state.applyList[index * 2] - .deviceId > - 31 - ? true - : false, - machine: machine[state - .applyList[index * 2].deviceType], - status: Status.working), - index * 2 + 1 < state.applyList.length - ? MachineCard( - index: state - .applyList[index * 2 + 1] - .deviceId, - isEnableNotification: false, - isWoman: - state.applyList[index * 2 + 1] - .deviceId > - 31 - ? true - : false, - machine: machine[state - .applyList[index * 2 + 1] - .deviceType], - status: Status.working) - : SizedBox( - width: 185.0.w, - height: 256.0.h, - ), - ], - ), - SizedBox(height: 10.0.h), - ], - ); - }), - ); - } else { - return const Center(child: CircularProgressIndicator()); - } - }, - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/setting_page/bloc/room_bloc.dart b/lib/presentation/setting_page/bloc/room_bloc.dart index 132e8ca5..b158dd1b 100644 --- a/lib/presentation/setting_page/bloc/room_bloc.dart +++ b/lib/presentation/setting_page/bloc/room_bloc.dart @@ -1,10 +1,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:lotura/domain/entity/room_entity.dart'; import 'package:lotura/domain/use_case/get_laundry_room_index_use_case.dart'; import 'package:lotura/domain/use_case/update_laundry_room_index_use_case.dart'; +import 'package:lotura/main.dart'; import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; import 'package:lotura/presentation/setting_page/bloc/room_state.dart'; -class RoomBloc extends Bloc { +class RoomBloc extends Bloc> { final GetLaundryRoomIndexUseCase _getLaundryRoomIndexUseCase; final UpdateLaundryRoomIndexUseCase _updateLaundryRoomIndexUseCase; @@ -13,19 +15,64 @@ class RoomBloc extends Bloc { required UpdateLaundryRoomIndexUseCase updateLaundryRoomIndexUseCase}) : _getLaundryRoomIndexUseCase = getLaundryRoomIndexUseCase, _updateLaundryRoomIndexUseCase = updateLaundryRoomIndexUseCase, - super(Initial()) { + super(Initial( + data: const LaundryRoomEntity( + roomLocation: RoomLocation.schoolSide, + buttonView: ButtonView.icon, + isClick: false, + isNFCShowBottomSheet: false, + showingBottomSheet: false))) { on(_updateRoomIndexEventHandler); on(_getRoomIndexEventHandler); + on(_modifyRoomIndexEventHandler); + on(_modifyPlaceIconIndexEventHandler); + on(_showBottomSheetEventHandler); + on(_initialShowBottomSheetEventHandler); + on(_showingBottomSheetEventHandler); + on(_closingBottomSheetEventHandler); } void _updateRoomIndexEventHandler( - UpdateRoomIndexEvent event, Emitter emit) { - emit(Changed(index: event.value)); - _updateLaundryRoomIndexUseCase.execute(value: event.value); + UpdateRoomIndexEvent event, Emitter> emit) { + emit(Changed(data: state.value.copyWith(roomLocation: event.roomLocation))); + _updateLaundryRoomIndexUseCase.execute(value: event.roomLocation.index); } void _getRoomIndexEventHandler( - GetRoomIndexEvent event, Emitter emit) { - emit(Changed(index: _getLaundryRoomIndexUseCase.execute)); + GetRoomIndexEvent event, Emitter> emit) { + emit(Changed( + data: state.value.copyWith( + roomLocation: RoomLocation.values + .elementAt(_getLaundryRoomIndexUseCase.execute)))); + } + + void _modifyRoomIndexEventHandler( + ModifyRoomIndexEvent event, Emitter> emit) { + emit(Changed(data: state.value.copyWith(roomLocation: event.roomLocation))); + } + + void _modifyPlaceIconIndexEventHandler( + ModifyButtonViewEvent event, Emitter> emit) { + emit(Changed(data: state.value.copyWith(buttonView: event.buttonView))); + } + + void _showBottomSheetEventHandler( + ShowBottomSheetEvent event, Emitter> emit) { + emit(Changed(data: state.value.copyWith(isNFCShowBottomSheet: true))); + } + + void _initialShowBottomSheetEventHandler(InitialShowBottomSheetEvent event, + Emitter> emit) { + emit(Changed(data: state.value.copyWith(isNFCShowBottomSheet: false))); + } + + void _showingBottomSheetEventHandler(ShowingBottomSheetEvent event, + Emitter> emit) { + emit(Changed(data: state.value.copyWith(showingBottomSheet: true))); + } + + void _closingBottomSheetEventHandler(ClosingBottomSheetEvent event, + Emitter> emit) { + emit(Changed(data: state.value.copyWith(showingBottomSheet: false))); } } diff --git a/lib/presentation/setting_page/bloc/room_event.dart b/lib/presentation/setting_page/bloc/room_event.dart index e3f5579c..c8f9c3b0 100644 --- a/lib/presentation/setting_page/bloc/room_event.dart +++ b/lib/presentation/setting_page/bloc/room_event.dart @@ -1,17 +1,31 @@ -import 'package:equatable/equatable.dart'; +import 'package:lotura/main.dart'; -abstract class RoomEvent extends Equatable {} +abstract class RoomEvent {} -class GetRoomIndexEvent extends RoomEvent { - @override - List get props => []; -} +class GetRoomIndexEvent extends RoomEvent {} class UpdateRoomIndexEvent extends RoomEvent { - final int value; + final RoomLocation roomLocation; + + UpdateRoomIndexEvent({required this.roomLocation}); +} + +class ModifyRoomIndexEvent extends RoomEvent { + final RoomLocation roomLocation; + + ModifyRoomIndexEvent({required this.roomLocation}); +} - UpdateRoomIndexEvent({required this.value}); +class ModifyButtonViewEvent extends RoomEvent { + final ButtonView buttonView; - @override - List get props => [value]; + ModifyButtonViewEvent({required this.buttonView}); } + +class ShowBottomSheetEvent extends RoomEvent {} + +class InitialShowBottomSheetEvent extends RoomEvent {} + +class ShowingBottomSheetEvent extends RoomEvent {} + +class ClosingBottomSheetEvent extends RoomEvent {} diff --git a/lib/presentation/setting_page/bloc/room_state.dart b/lib/presentation/setting_page/bloc/room_state.dart index cff717bc..176f8b49 100644 --- a/lib/presentation/setting_page/bloc/room_state.dart +++ b/lib/presentation/setting_page/bloc/room_state.dart @@ -1,17 +1,23 @@ -import 'package:equatable/equatable.dart'; +enum RoomStateEnum { initial, changed } -abstract class RoomState extends Equatable {} +sealed class RoomState { + RoomState({required this.roomState, required this.value, this.error}); -class Initial extends RoomState { - @override - List get props => []; + T value; + Object? error; + RoomStateEnum roomState; } -class Changed extends RoomState { - final int index; +class Initial extends RoomState { + final T data; - Changed({required this.index}); + Initial({required this.data}) + : super(roomState: RoomStateEnum.initial, value: data); +} + +class Changed extends RoomState { + final T data; - @override - List get props => [index]; + Changed({required this.data}) + : super(roomState: RoomStateEnum.changed, value: data); } diff --git a/lib/presentation/setting_page/ui/view/setting_page.dart b/lib/presentation/setting_page/ui/view/setting_page.dart index b26bd6b6..e4f299d1 100644 --- a/lib/presentation/setting_page/ui/view/setting_page.dart +++ b/lib/presentation/setting_page/ui/view/setting_page.dart @@ -1,11 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:lotura/domain/entity/room_entity.dart'; import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; import 'package:lotura/presentation/setting_page/bloc/room_state.dart'; import 'package:lotura/presentation/setting_page/ui/widget/setting_page_bottom_sheet.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; import 'package:url_launcher/url_launcher.dart'; class SettingPage extends StatefulWidget { @@ -16,28 +17,18 @@ class SettingPage extends StatefulWidget { } class _SettingPageState extends State { - String mainLaundryRoom = ""; - - final Map place = { - 0: "남자 학교측 세탁실", - 1: "남자 기숙사측 세탁실", - 2: "여자 세탁실", - }; - @override void initState() { super.initState(); context.read().add(GetRoomIndexEvent()); - //initSharedPreferences(); } @override Widget build(BuildContext context) { - //initSharedPreferences(); return Scaffold( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, appBar: AppBar( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, elevation: 0.0, leadingWidth: 300.0.w, leading: Row( @@ -47,13 +38,13 @@ class _SettingPageState extends State { onPressed: () => Navigator.pop(context), icon: Icon( Icons.keyboard_arrow_left, - color: OSJColors.black, + color: LoturaColors.black, size: 24.0.w, ), ), Text( "설정", - style: TextStyle(fontSize: 24.0.sp, color: OSJColors.black), + style: TextStyle(fontSize: 24.0.sp, color: LoturaColors.black), ), ], ), @@ -78,40 +69,39 @@ class _SettingPageState extends State { ), Row( children: [ - BlocBuilder( + BlocBuilder>( builder: (context, state) { - if (state is Initial) { - return const SizedBox.shrink(); - } else if (state is Changed) { - return GestureDetector( - onTap: () => showModalBottomSheet( - context: context, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(24.r), + return switch (state) { + Initial() => const SizedBox.shrink(), + Changed() => GestureDetector( + onTap: () => showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(24.r), + ), ), + backgroundColor: LoturaColors.white, + builder: (context) => + SettingPageBottomSheet( + initialIndex: + state.value.roomLocation.index, + )), + child: Text( + state.value.roomLocation.roomName, + style: TextStyle( + fontSize: 16.0.sp, + color: LoturaColors.primary700, ), - backgroundColor: OSJColors.white, - builder: (context) => SettingPageBottomSheet( - initialIndex: state.index, - )), - child: Text( - place[state.index], - style: TextStyle( - fontSize: 16.0.sp, - color: OSJColors.primary700, ), ), - ); - } else { - return const SizedBox.shrink(); - } + }; }, ), SizedBox(width: 12.0.w), Icon( Icons.keyboard_arrow_right, - color: OSJColors.gray300, + color: LoturaColors.gray300, size: 24.0.r, ), ], @@ -141,7 +131,7 @@ class _SettingPageState extends State { ), Icon( Icons.keyboard_arrow_right, - color: OSJColors.gray300, + color: LoturaColors.gray300, size: 24.0.r, ), ], diff --git a/lib/presentation/setting_page/ui/widget/setting_page_bottom_sheet.dart b/lib/presentation/setting_page/ui/widget/setting_page_bottom_sheet.dart index 1fe36d8f..5541600d 100644 --- a/lib/presentation/setting_page/ui/widget/setting_page_bottom_sheet.dart +++ b/lib/presentation/setting_page/ui/widget/setting_page_bottom_sheet.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:lotura/domain/entity/room_entity.dart'; +import 'package:lotura/main.dart'; import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; import 'package:lotura/presentation/setting_page/bloc/room_state.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; class SettingPageBottomSheet extends StatelessWidget { final int initialIndex; @@ -13,7 +15,8 @@ class SettingPageBottomSheet extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder(builder: (context, state) { + return BlocBuilder>( + builder: (context, state) { if (state is Initial) { context.read().add(GetRoomIndexEvent()); return const SizedBox.shrink(); @@ -33,27 +36,28 @@ class SettingPageBottomSheet extends StatelessWidget { Text( "메인 세탁실 설정", style: TextStyle( - color: OSJColors.black, + color: LoturaColors.black, fontWeight: FontWeight.w600, fontSize: 20.0.sp), ), SizedBox(height: 4.0.h), Text( "세탁실 탭에서 처음에 보여질 세탁실을 선택해보세요.", - style: TextStyle(fontSize: 16.0.sp, color: OSJColors.black), + style: + TextStyle(fontSize: 16.0.sp, color: LoturaColors.black), ), SizedBox(height: 24.0.h), GestureDetector( - onTap: () => context - .read() - .add(UpdateRoomIndexEvent(value: 0)), + onTap: () => context.read().add( + UpdateRoomIndexEvent( + roomLocation: RoomLocation.schoolSide)), child: Container( width: 382.0.w, height: 48.0.h, decoration: BoxDecoration( - color: state.index == 0 - ? OSJColors.gray100 - : OSJColors.white, + color: state.value.roomLocation == RoomLocation.schoolSide + ? LoturaColors.gray100 + : LoturaColors.white, borderRadius: BorderRadius.circular(8.0), ), padding: EdgeInsets.all(12.0.r), @@ -64,31 +68,33 @@ class SettingPageBottomSheet extends StatelessWidget { "남자 학교측", style: TextStyle( fontSize: 16.0.sp, - color: OSJColors.black, + color: LoturaColors.black, ), ), Icon( Icons.check, size: 24.0.r, - color: state.index == 0 - ? OSJColors.black - : OSJColors.white, + color: state.value.roomLocation == + RoomLocation.schoolSide + ? LoturaColors.black + : LoturaColors.white, ), ], ), ), ), GestureDetector( - onTap: () => context - .read() - .add(UpdateRoomIndexEvent(value: 1)), + onTap: () => context.read().add( + UpdateRoomIndexEvent( + roomLocation: RoomLocation.dormitorySide)), child: Container( width: 382.0.w, height: 48.0.h, decoration: BoxDecoration( - color: state.index == 1 - ? OSJColors.gray100 - : OSJColors.white, + color: + state.value.roomLocation == RoomLocation.dormitorySide + ? LoturaColors.gray100 + : LoturaColors.white, borderRadius: BorderRadius.circular(8.0), ), padding: EdgeInsets.all(12.0.r), @@ -99,31 +105,32 @@ class SettingPageBottomSheet extends StatelessWidget { "남자 기숙사측", style: TextStyle( fontSize: 16.0.sp, - color: OSJColors.black, + color: LoturaColors.black, ), ), Icon( Icons.check, size: 24.0.r, - color: state.index == 1 - ? OSJColors.black - : OSJColors.white, + color: state.value.roomLocation == + RoomLocation.dormitorySide + ? LoturaColors.black + : LoturaColors.white, ), ], ), ), ), GestureDetector( - onTap: () => context - .read() - .add(UpdateRoomIndexEvent(value: 2)), + onTap: () => context.read().add( + UpdateRoomIndexEvent( + roomLocation: RoomLocation.womanRoom)), child: Container( width: 382.0.w, height: 48.0.h, decoration: BoxDecoration( - color: state.index == 2 - ? OSJColors.gray100 - : OSJColors.white, + color: state.value.roomLocation == RoomLocation.womanRoom + ? LoturaColors.gray100 + : LoturaColors.white, borderRadius: BorderRadius.circular(8.0), ), padding: EdgeInsets.all(12.0.r), @@ -134,15 +141,16 @@ class SettingPageBottomSheet extends StatelessWidget { "여자", style: TextStyle( fontSize: 16.0.sp, - color: OSJColors.black, + color: LoturaColors.black, ), ), Icon( Icons.check, size: 24.0.r, - color: state.index == 2 - ? OSJColors.black - : OSJColors.white, + color: + state.value.roomLocation == RoomLocation.womanRoom + ? LoturaColors.black + : LoturaColors.white, ), ], ), diff --git a/lib/presentation/splash_page/ui/view/splash_page.dart b/lib/presentation/splash_page/ui/view/splash_page.dart index 7117a48d..ef179d38 100644 --- a/lib/presentation/splash_page/ui/view/splash_page.dart +++ b/lib/presentation/splash_page/ui/view/splash_page.dart @@ -1,47 +1,75 @@ import 'dart:async'; +import 'dart:io'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:lotura/data/dto/request/get_apply_list_request.dart'; -import 'package:lotura/presentation/laundry_room_page/bloc/laundry_event.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_bloc.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_event.dart'; +import 'package:lotura/presentation/app_update_page/ui/app_update_page.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_event.dart'; import 'package:lotura/presentation/laundry_room_page/bloc/laundry_bloc.dart'; +import 'package:lotura/presentation/laundry_room_page/bloc/laundry_event.dart'; import 'package:lotura/presentation/utils/bottom_navi.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; +import 'package:package_info_plus/package_info_plus.dart'; class SplashPage extends StatefulWidget { - const SplashPage({super.key}); + const SplashPage({super.key, required this.nfcTagData}); + + final int nfcTagData; @override State createState() => _SplashPageState(); } class _SplashPageState extends State { + Future checkAppVersion() async { + final remoteConfig = FirebaseRemoteConfig.instance; + await remoteConfig.fetchAndActivate(); + + String firebaseVersion = remoteConfig.getString( + Platform.isAndroid ? "ANDROID_APP_VERSION" : "iOS_APP_VERSION"); + + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + String appVersion = packageInfo.version; + + if (firebaseVersion != appVersion) { + Future.delayed(Duration.zero).then((value) => + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const AppUpdatePage()), + (route) => false)); + } else { + Future.delayed(const Duration(seconds: 1)).then( + (value) { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => BottomNavi(nfcTagData: widget.nfcTagData), + ), + (route) => false); + }, + ); + } + } + @override void initState() { super.initState(); + checkAppVersion(); + context.read().add(GetAllLaundryListEvent()); context.read().add(GetLaundryEvent()); context .read() .add(GetApplyListEvent(getApplyListRequest: GetApplyListRequest())); - Future.delayed(const Duration(milliseconds: 1100)).then( - (value) { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - builder: (context) => BottomNavi(), - ), - (route) => false); - }, - ); } @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -52,10 +80,10 @@ class _SplashPageState extends State { height: 100.0.r, ), SizedBox(height: 12.0.h), - Text( + const Text( 'OSJ', style: TextStyle( - color: OSJColors.primary700, + color: LoturaColors.primary700, fontSize: 40, fontWeight: FontWeight.w700, ), diff --git a/lib/presentation/utils/bottom_navi.dart b/lib/presentation/utils/bottom_navi.dart index a7763a9d..c130b6f1 100644 --- a/lib/presentation/utils/bottom_navi.dart +++ b/lib/presentation/utils/bottom_navi.dart @@ -1,28 +1,111 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:lotura/data/dto/request/get_apply_list_request.dart'; +import 'package:lotura/main.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_event.dart'; +import 'package:lotura/presentation/apply_page/ui/view/apply_page.dart'; +import 'package:lotura/presentation/laundry_room_page/bloc/laundry_bloc.dart'; +import 'package:lotura/presentation/laundry_room_page/bloc/laundry_event.dart'; import 'package:lotura/presentation/laundry_room_page/ui/view/laundry_room_page.dart'; -import 'package:lotura/presentation/main_page/ui/view/main_page.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; +import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; import 'package:lotura/presentation/utils/osj_icon_button.dart'; import 'package:lotura/presentation/utils/osj_image_button.dart'; class BottomNavi extends StatefulWidget { - const BottomNavi({super.key}); + BottomNavi({super.key, required this.nfcTagData}); + + int nfcTagData; @override State createState() => _BottomNaviState(); } class _BottomNaviState extends State - with SingleTickerProviderStateMixin { + with SingleTickerProviderStateMixin, WidgetsBindingObserver { late TabController controller; + final platformMsg = const MethodChannel('com.osj.lotura/nfc_info'); int selectedIndex = 1; bool isChange = false; + final Map placeIndex = {0: 0, 1: 16, 2: 31, 3: 44}; + @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); + if (Platform.isAndroid) { + const MethodChannel('com.osj.lotura/nfc_info') + .invokeMethod('nfcIsAvailable') + .then( + (value) { + if (value.toString() == "false") { + WidgetsBinding.instance.addPostFrameCallback( + (_) { + Hive.openBox("Lotura").then( + (value) { + if (value.get('다시 보지 않기') == null) { + showDialog( + context: context, + builder: (context) => Center( + child: AlertDialog( + title: Text( + "NFC가 비활성화 되어있습니다.", + style: TextStyle(fontSize: 20.0.sp), + ), + content: Text( + "Lotura 서비스 이용을 위해\n스마트폰의 NFC를 설정해주세요.", + style: TextStyle(fontSize: 18.0.sp), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + actionsAlignment: MainAxisAlignment.spaceEvenly, + actions: [ + MaterialButton( + onPressed: () { + value.put('다시 보지 않기', 1); + Navigator.of(context).pop(); + }, + child: Text("다시 보지 않기", + style: TextStyle(fontSize: 16.0.sp))), + MaterialButton( + onPressed: () => Navigator.of(context).pop(), + child: Text("닫기", + style: TextStyle(fontSize: 16.0.sp))), + ], + ), + ), + ); + } + }, + ); + }, + ); + } + }, + ); + } + if (widget.nfcTagData != -1) { + for (var i in placeIndex.entries) { + if (i.value > widget.nfcTagData - 1) { + context.read().add(ModifyRoomIndexEvent( + roomLocation: RoomLocation.values.elementAt(i.key - 1))); + break; + } + } + } else { + context.read().add(GetRoomIndexEvent()); + } controller = TabController(length: 2, vsync: this) ..index = 1 ..animation?.addListener(() { @@ -66,21 +149,52 @@ class _BottomNaviState extends State }); } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + switch (state) { + case AppLifecycleState.resumed: + platformMsg.invokeMethod("getNFCInfo").then((value) { + widget.nfcTagData = (jsonDecode(value)['index'] as int); + if (widget.nfcTagData != -1) { + selectedIndex = 1; + controller.index = 1; + for (var i in placeIndex.entries) { + if (i.value > widget.nfcTagData - 1) { + context.read().add(ModifyRoomIndexEvent( + roomLocation: RoomLocation.values.elementAt(i.key - 1))); + break; + } + } + BlocProvider.of(context) + .add(InitialShowBottomSheetEvent()); + setState(() {}); + } + }); + BlocProvider.of(context).add(GetAllLaundryListEvent()); + BlocProvider.of(context).add(GetLaundryEvent()); + BlocProvider.of(context) + .add(GetApplyListEvent(getApplyListRequest: GetApplyListRequest())); + default: + } + } + @override void dispose() { super.dispose(); controller.dispose(); + WidgetsBinding.instance.removeObserver(this); } @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: OSJColors.gray100, + backgroundColor: LoturaColors.gray100, body: TabBarView( controller: controller, children: [ - MainPage(), - const LaundryRoomPage(), + ApplyPage(), + LaundryRoomPage(nfcTagData: widget.nfcTagData), ], ), bottomNavigationBar: TabBar( @@ -92,14 +206,18 @@ class _BottomNaviState extends State width: 185.0.w, height: 48.0.h, iconSize: 24.0.r, - color: selectedIndex == 0 ? OSJColors.white : OSJColors.gray100, - iconColor: - selectedIndex == 0 ? OSJColors.primary700 : OSJColors.gray300, + color: selectedIndex == 0 + ? LoturaColors.white + : LoturaColors.gray100, + iconColor: selectedIndex == 0 + ? LoturaColors.primary700 + : LoturaColors.gray300, iconData: Icons.home), OSJImageButton( width: 185.0.w, height: 48.0.h, - color: selectedIndex == 1 ? OSJColors.white : OSJColors.gray100, + color: + selectedIndex == 1 ? LoturaColors.white : LoturaColors.gray100, imagePath: selectedIndex == 1 ? "assets/applogo.jpeg" : "assets/applogo_unselected.jpeg", diff --git a/lib/presentation/utils/lotura_colors.dart b/lib/presentation/utils/lotura_colors.dart new file mode 100644 index 00000000..cd417cea --- /dev/null +++ b/lib/presentation/utils/lotura_colors.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class LoturaColors { + LoturaColors._(); + + static const Color customGreen = Color(0xFF7DB45A); + static const Color customRed = Color(0xFFDA6156); + + static const Color primary900 = Color(0xff164ED4); + static const Color primary700 = Color(0xff3C70EC); + static const Color primary500 = Color(0xff7599ED); + static const Color primary300 = Color(0xff98B1ED); + static const Color primary100 = Color(0xffEBF1FF); + static const Color primary50 = Color(0xffFAFBFF); + + static const Color green700 = Color(0xff25BD1D); + static const Color green100 = Color(0xffECFFEB); + static const Color green50 = Color(0xffF8FFF8); + + static const Color red700 = Color(0xffD91F1F); + static const Color red100 = Color(0xffFFEBEB); + static const Color red50 = Color(0xffFFFAFA); + + static const Color black = Color(0xff000000); + static const Color gray900 = Color(0xff1D1F22); + static const Color gray700 = Color(0xff2E3135); + static const Color gray500 = Color(0xff676C74); + static const Color gray300 = Color(0xffADB3BD); + static const Color gray100 = Color(0xffF0F3F6); + static const Color white = Color(0xffFFFFFF); +} diff --git a/lib/presentation/utils/machine_button.dart b/lib/presentation/utils/machine_button.dart index 9347f75f..98e1e71a 100644 --- a/lib/presentation/utils/machine_button.dart +++ b/lib/presentation/utils/machine_button.dart @@ -1,56 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:lotura/main.dart'; -import 'package:lotura/presentation/utils/lotura_icons.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; import 'package:lotura/presentation/utils/machine_widget.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; class MachineButton extends MachineWidget { - MachineButton({ + const MachineButton({ super.key, - required int index, - required bool isEnableNotification, - required bool isWoman, - required Status status, - required Machine machine, - }) : super( - index: index, - isEnableNotification: isEnableNotification, - isWoman: isWoman, - status: status, - machine: machine, - ); - - final Map statusColor = { - Status.available: OSJColors.green50, - Status.working: OSJColors.primary50, - Status.disconnected: OSJColors.white, - Status.breakdown: OSJColors.red50, - }; - - final Map statusIconColor = { - Status.available: OSJColors.green700, - Status.working: OSJColors.primary700, - Status.disconnected: OSJColors.black, - Status.breakdown: OSJColors.red700, - }; - - final Map statusIcon = { - Status.available: LoturaIcons.checkCircle, - Status.working: LoturaIcons.working, - Status.disconnected: LoturaIcons.disconnected, - Status.breakdown: LoturaIcons.cancelCircle, - }; - - final Map machineIcon = { - Machine.wash: LoturaIcons.laundry, - Machine.dry: LoturaIcons.dry, - }; - - final Map machineText = { - Machine.wash: "세탁기", - Machine.dry: "건조기", - }; + required super.index, + required super.isEnableNotification, + required super.isWoman, + required super.state, + required super.machine, + }); @override Widget build(BuildContext context) { @@ -62,7 +23,7 @@ class MachineButton extends MachineWidget { width: 154.0.w, height: 84.0.h, decoration: BoxDecoration( - color: statusColor[status], + color: state.color, borderRadius: BorderRadius.circular(16.0), ), child: Padding( @@ -72,8 +33,8 @@ class MachineButton extends MachineWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Icon(machineIcon[machine], - size: 24.0.r, color: OSJColors.gray300), + Icon(machine.icon, + size: 24.0.r, color: LoturaColors.gray300), Row( children: [ Text("${isWoman ? index - 31 : index}번", @@ -82,13 +43,12 @@ class MachineButton extends MachineWidget { width: (isWoman ? index - 31 : index) < 10 ? 10.2.w : 5.0.w), - Text(machineText[machine], - style: TextStyle(fontSize: 16.0.sp)), + Text(machine.text, style: TextStyle(fontSize: 16.0.sp)), SizedBox(width: 8.0.w), Icon( - statusIcon[status], + state.icon, size: 18.0.r, - color: statusIconColor[status], + color: state.deepColor, ), ], ), diff --git a/lib/presentation/utils/machine_card.dart b/lib/presentation/utils/machine_card.dart index 5207e517..f1226561 100644 --- a/lib/presentation/utils/machine_card.dart +++ b/lib/presentation/utils/machine_card.dart @@ -1,24 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:lotura/main.dart'; import 'package:lotura/presentation/utils/machine_widget.dart'; import 'package:lotura/presentation/utils/osj_status_button.dart'; class MachineCard extends MachineWidget { const MachineCard({ super.key, - required int index, - required bool isEnableNotification, - required bool isWoman, - required Machine machine, - required Status status, - }) : super( - index: index, - isEnableNotification: isEnableNotification, - isWoman: isWoman, - machine: machine, - status: status, - ); + required super.index, + required super.isEnableNotification, + required super.isWoman, + required super.machine, + required super.state, + }); @override Widget build(BuildContext context) { @@ -61,7 +54,9 @@ class MachineCard extends MachineWidget { ], ), SizedBox(height: 12.0.h), - OSJStatusButton(status: status), + OSJStatusButton( + state: state, + ), ], ), ), diff --git a/lib/presentation/utils/machine_widget.dart b/lib/presentation/utils/machine_widget.dart index 1a9217d0..7d141a4c 100644 --- a/lib/presentation/utils/machine_widget.dart +++ b/lib/presentation/utils/machine_widget.dart @@ -9,14 +9,14 @@ abstract class MachineWidget extends StatelessWidget { required this.index, required this.isEnableNotification, required this.isWoman, - required this.status, + required this.state, required this.machine, }); final int index; final bool isEnableNotification, isWoman; - final Status status; + final CurrentState state; final Machine machine; @@ -35,7 +35,7 @@ abstract class MachineWidget extends StatelessWidget { index: index, isEnableNotification: isEnableNotification, isWoman: isWoman, - status: status, + state: state, machine: machine, ), ); diff --git a/lib/presentation/utils/osj_bottom_sheet.dart b/lib/presentation/utils/osj_bottom_sheet.dart index cef53548..f11d109e 100644 --- a/lib/presentation/utils/osj_bottom_sheet.dart +++ b/lib/presentation/utils/osj_bottom_sheet.dart @@ -4,168 +4,180 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:lotura/data/dto/request/apply_cancel_request.dart'; import 'package:lotura/data/dto/request/send_fcm_info_request.dart'; import 'package:lotura/main.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_bloc.dart'; -import 'package:lotura/presentation/main_page/bloc/apply_event.dart'; -import 'package:lotura/presentation/utils/lotura_icons.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_bloc.dart'; +import 'package:lotura/presentation/apply_page/bloc/apply_event.dart'; +import 'package:lotura/presentation/setting_page/bloc/room_bloc.dart'; +import 'package:lotura/presentation/setting_page/bloc/room_event.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; import 'package:lotura/presentation/utils/osj_text_button.dart'; -class OSJBottomSheet extends StatelessWidget { - OSJBottomSheet({ +class OSJBottomSheet extends StatefulWidget { + const OSJBottomSheet({ super.key, required this.index, required this.isEnableNotification, required this.isWoman, - required this.status, + required this.state, required this.machine, }); final int index; final bool isEnableNotification, isWoman; - final Status status; + final CurrentState state; final Machine machine; - final Map statusColor = { - Status.available: OSJColors.green50, - Status.working: OSJColors.primary50, - Status.disconnected: OSJColors.black, - Status.breakdown: OSJColors.red50, - }; - - final Map statusIcon = { - Status.available: LoturaIcons.checkCircle, - Status.working: LoturaIcons.working, - Status.disconnected: LoturaIcons.disconnected, - Status.breakdown: LoturaIcons.cancelCircle, - }; - - final Map machineIcon = { - Machine.wash: LoturaIcons.laundry, - Machine.dry: LoturaIcons.dry, - }; - - final Map machineText = { - Machine.wash: "세탁기", - Machine.dry: "건조기", - }; + @override + State createState() => _OSJBottomSheetState(); +} - String text(bool isEnableNotification, isWoman, Status status) { +class _OSJBottomSheetState extends State { + String text(bool isEnableNotification, isWoman, CurrentState state) { if (isEnableNotification) { if (isWoman) { - switch (status) { - case Status.working: - return "여자 세탁실 ${index - 31}번 ${machineText[machine]}를\n알림 설정 하실건가요?"; - case Status.available: - return "여자 세탁실 ${index - 31}번 ${machineText[machine]}는\n현재 사용 가능한 상태에요."; - case Status.disconnected: - return "여자층 ${index - 31}번 ${machineText[machine]}의 연결이 끊겨서\n상태를 확인할 수 없어요."; - case Status.breakdown: - return "여자 세탁실 ${index - 31}번 ${machineText[machine]}는\n고장으로 인해 사용이 불가능해요."; + switch (state) { + case CurrentState.working: + return "여자 세탁실 ${widget.index - 31}번 ${widget.machine.text}를\n알림 설정 하실건가요?"; + case CurrentState.available: + return "여자 세탁실 ${widget.index - 31}번 ${widget.machine.text}는\n현재 사용 가능한 상태에요."; + case CurrentState.disconnected: + return "여자층 ${widget.index - 31}번 ${widget.machine.text}의 연결이 끊겨서\n상태를 확인할 수 없어요."; + case CurrentState.breakdown: + return "여자 세탁실 ${widget.index - 31}번 ${widget.machine.text}는\n고장으로 인해 사용이 불가능해요."; } } else { - switch (status) { - case Status.working: - return "$index번 ${machineText[machine]}를\n알림 설정 하실건가요?"; - case Status.available: - return "$index번 ${machineText[machine]}는\n현재 사용 가능한 상태에요."; - case Status.disconnected: - return "$index번 ${machineText[machine]}의 연결이 끊겨서\n상태를 확인할 수 없어요."; - case Status.breakdown: - return "$index번 ${machineText[machine]}는\n고장으로 인해 사용이 불가능해요."; + switch (state) { + case CurrentState.working: + return "${widget.index}번 ${widget.machine.text}를\n알림 설정 하실건가요?"; + case CurrentState.available: + return "${widget.index}번 ${widget.machine.text}는\n현재 사용 가능한 상태에요."; + case CurrentState.disconnected: + return "${widget.index}번 ${widget.machine.text}의 연결이 끊겨서\n상태를 확인할 수 없어요."; + case CurrentState.breakdown: + return "${widget.index}번 ${widget.machine.text}는\n고장으로 인해 사용이 불가능해요."; } } } else { if (isWoman) { - return "여자 세탁실 ${index - 31}번 ${machineText[machine]}의\n알림 설정을 해제하실건가요?"; + return "여자 세탁실 ${widget.index - 31}번 ${widget.machine.text}의\n알림 설정을 해제하실건가요?"; } else { - return "$index번 ${machineText[machine]}의\n알림 설정을 해제하실건가요?"; + return "${widget.index}번 ${widget.machine.text}의\n알림 설정을 해제하실건가요?"; } } } + @override + void initState() { + super.initState(); + context.read().add(ShowingBottomSheetEvent()); + } + @override Widget build(BuildContext context) { - return SizedBox( - width: double.infinity, - height: status == Status.working ? 220.0.h : 268.0.h, - child: Padding( - padding: EdgeInsets.only( - left: 24.0.w, - right: 24.0.w, - top: 32.0.h, - bottom: 12.0.h, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - status == Status.working - ? const SizedBox.shrink() - : Icon( - statusIcon[status], - size: 24.0.r, - color: status == Status.available - ? OSJColors.green700 - : status == Status.disconnected - ? OSJColors.black - : OSJColors.red700, + return PopScope( + onPopInvoked: (_) async { + context.read().add(ClosingBottomSheetEvent()); + return Future(() => true); + }, + child: SizedBox( + width: double.infinity, + height: widget.state == CurrentState.working ? 220.0.h : 268.0.h, + child: Padding( + padding: EdgeInsets.only( + left: 24.0.w, + right: 24.0.w, + top: 32.0.h, + bottom: 12.0.h, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.state == CurrentState.working + ? const SizedBox.shrink() + : Icon( + widget.state.icon, + size: 24.0.r, + color: widget.state == CurrentState.available + ? LoturaColors.green700 + : widget.state == CurrentState.disconnected + ? LoturaColors.black + : LoturaColors.red700, + ), + Padding( + padding: widget.state == CurrentState.working + ? EdgeInsets.only(bottom: 24.0.h) + : EdgeInsets.only(top: 24.0.h, bottom: 24.0.h), + child: Text( + text(widget.isEnableNotification, widget.isWoman, + widget.state), + style: TextStyle( + color: Colors.black, + fontSize: 22.0.sp, + fontWeight: FontWeight.w600, ), - Padding( - padding: status == Status.working - ? EdgeInsets.only(bottom: 24.0.h) - : EdgeInsets.only(top: 24.0.h, bottom: 24.0.h), - child: Text( - text(isEnableNotification, isWoman, status), - style: TextStyle( - color: Colors.black, - fontSize: 22.0.sp, - fontWeight: FontWeight.w600, ), ), - ), - status == Status.working - ? Row( - children: [ - OSJTextButton( - function: () => Navigator.of(context).pop(), - width: 185.0.w, - height: 56.0.h, - fontSize: 16.0.sp, - color: OSJColors.gray100, - fontColor: OSJColors.black, - text: "취소"), - SizedBox(width: 12.0.w), - OSJTextButton( + widget.state == CurrentState.working + ? Row( + children: [ + OSJTextButton( + function: () { + Navigator.of(context).pop(); + context + .read() + .add(ClosingBottomSheetEvent()); + }, + width: 185.0.w, + height: 56.0.h, + fontSize: 16.0.sp, + color: LoturaColors.gray100, + fontColor: LoturaColors.black, + text: "취소"), + SizedBox(width: 12.0.w), + OSJTextButton( + function: () { + widget.isEnableNotification + ? context.read().add(SendFCMEvent( + sendFCMInfoRequest: SendFCMInfoRequest( + deviceId: widget.index.toString(), + expectState: '1'))) + : context.read().add( + ApplyCancelEvent( + applyCancelRequest: + ApplyCancelRequest( + deviceId: widget.index + .toString()))); + context + .read() + .add(ClosingBottomSheetEvent()); + Navigator.pop(context); + }, + width: 185.0.w, + height: 56.0.h, + fontSize: 16.0.sp, + color: LoturaColors.primary700, + fontColor: LoturaColors.white, + text: widget.isEnableNotification + ? "알림 설정" + : "알림 해제"), + ], + ) + : Center( + child: OSJTextButton( function: () { - isEnableNotification - ? context.read().add(SendFCMEvent( - sendFCMInfoRequest: SendFCMInfoRequest( - deviceId: index.toString(), - expectState: '1'))) - : context.read().add( - ApplyCancelEvent( - applyCancelRequest: ApplyCancelRequest( - deviceId: index.toString()))); - Navigator.pop(context); + context + .read() + .add(ClosingBottomSheetEvent()); + Navigator.of(context).pop(); }, - width: 185.0.w, + width: 382.0.w, height: 56.0.h, fontSize: 16.0.sp, - color: OSJColors.primary700, - fontColor: OSJColors.white, - text: isEnableNotification ? "알림 설정" : "알림 해제"), - ], - ) - : Center( - child: OSJTextButton( - function: () => Navigator.of(context).pop(), - width: 382.0.w, - height: 56.0.h, - fontSize: 16.0.sp, - color: OSJColors.gray100, - fontColor: OSJColors.black, - text: "확인"), - ), - ], + color: LoturaColors.gray100, + fontColor: LoturaColors.black, + text: "확인"), + ), + ], + ), ), ), ); diff --git a/lib/presentation/utils/osj_colors.dart b/lib/presentation/utils/osj_colors.dart deleted file mode 100644 index 3ee7c5ba..00000000 --- a/lib/presentation/utils/osj_colors.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; - -class OSJColors { - static Color customGreen = const Color(0xFF7DB45A); - static Color customRed = const Color(0xFFDA6156); - - static Color primary900 = const Color(0xff164ED4); - static Color primary700 = const Color(0xff3C70EC); - static Color primary500 = const Color(0xff7599ED); - static Color primary300 = const Color(0xff98B1ED); - static Color primary100 = const Color(0xffEBF1FF); - static Color primary50 = const Color(0xffFAFBFF); - - static Color green700 = const Color(0xff25BD1D); - static Color green100 = const Color(0xffECFFEB); - static Color green50 = const Color(0xffF8FFF8); - - static Color red700 = const Color(0xffD91F1F); - static Color red100 = const Color(0xffFFEBEB); - static Color red50 = const Color(0xffFFFAFA); - - static Color black = const Color(0xff000000); - static Color gray900 = const Color(0xff1D1F22); - static Color gray700 = const Color(0xff2E3135); - static Color gray500 = const Color(0xff676C74); - static Color gray300 = const Color(0xffADB3BD); - static Color gray100 = const Color(0xffF0F3F6); - static Color white = const Color(0xffFFFFFF); -} diff --git a/lib/presentation/utils/osj_status_button.dart b/lib/presentation/utils/osj_status_button.dart index 8d8cc7c4..af193fbd 100644 --- a/lib/presentation/utils/osj_status_button.dart +++ b/lib/presentation/utils/osj_status_button.dart @@ -1,35 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:lotura/main.dart'; -import 'package:lotura/presentation/utils/osj_colors.dart'; +import 'package:lotura/presentation/utils/lotura_colors.dart'; class OSJStatusButton extends StatelessWidget { OSJStatusButton({ super.key, - required this.status, + required this.state, }); - final Status status; + final CurrentState state; - final Map map = { - Status.available: "사용 가능", - Status.working: "작동중", - Status.disconnected: "연결 끊김", - Status.breakdown: "고장", - }; - - final Map statusColor = { - Status.available: OSJColors.green100, - Status.working: OSJColors.primary100, - Status.disconnected: OSJColors.gray300, - Status.breakdown: OSJColors.red100, - }; - - final Map statusTextColor = { - Status.available: OSJColors.green700, - Status.working: OSJColors.primary700, - Status.disconnected: OSJColors.black, - Status.breakdown: OSJColors.red700, + final Map stateColor = { + CurrentState.available: LoturaColors.green100, + CurrentState.working: LoturaColors.primary100, + CurrentState.disconnected: LoturaColors.gray300, + CurrentState.breakdown: LoturaColors.red100, }; @override @@ -39,13 +25,13 @@ class OSJStatusButton extends StatelessWidget { height: 32.0.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100.0), - color: statusColor[status], + color: stateColor[state], ), child: Center( child: Text( - map[status].toString(), + state.text, style: TextStyle( - color: statusTextColor[status], + color: state.deepColor, fontSize: 14.0.sp, ), ), diff --git a/pubspec.lock b/pubspec.lock index 9951e97b..03656cd4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" convert: dependency: transitive description: @@ -193,6 +193,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.5.18" + firebase_remote_config: + dependency: "direct main" + description: + name: firebase_remote_config + sha256: "60fc92273d1db338a6fad1839c42dedc4ad64f812043acad0cbb200702f5c9ce" + url: "https://pub.dev" + source: hosted + version: "4.3.8" + firebase_remote_config_platform_interface: + dependency: transitive + description: + name: firebase_remote_config_platform_interface + sha256: "41813ef8dfbc40ef7a59a73f9e5acef2608dbcb2933241b6c03d52e90677040f" + url: "https://pub.dev" + source: hosted + version: "1.4.16" + firebase_remote_config_web: + dependency: transitive + description: + name: firebase_remote_config_web + sha256: "089e92f333c2fb2c05c640c80fecea9d1e06dada0ba85efe34a580987ef94a0a" + url: "https://pub.dev" + source: hosted + version: "1.4.16" flutter: dependency: "direct main" description: flutter @@ -226,10 +250,10 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: "892ada16046d641263f30c72e7432397088810a84f34479f6677494802a2b535" + sha256: c18f1de98fe0bb9dd5ba91e1330d4febc8b6a7de6aae3ffe475ef423723e72f3 url: "https://pub.dev" source: hosted - version: "16.3.0" + version: "16.3.2" flutter_local_notifications_linux: dependency: transitive description: @@ -300,10 +324,10 @@ packages: dependency: transitive description: name: image - sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + sha256: "49a0d4b0c12402853d3f227fe7c315601b238d126aa4caa5dbb2dcf99421aa4a" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.6" js: dependency: transitive description: @@ -320,46 +344,62 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.1" - lints: + leak_tracker: dependency: transitive description: - name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" url: "https://pub.dev" source: hosted - version: "3.0.0" - logging: + version: "10.0.0" + leak_tracker_flutter_testing: dependency: transitive description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.11.0" nested: dependency: transitive description: @@ -368,22 +408,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_android: dependency: transitive description: @@ -396,10 +452,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -412,10 +468,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -452,10 +508,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" provider: dependency: transitive description: @@ -469,22 +525,6 @@ packages: description: flutter source: sdk version: "0.0.99" - socket_io_client: - dependency: "direct main" - description: - name: socket_io_client - sha256: ede469f3e4c55e8528b4e023bdedbc20832e8811ab9b61679d1ba3ed5f01f23b - url: "https://pub.dev" - source: hosted - version: "2.0.3+1" - socket_io_common: - dependency: transitive - description: - name: socket_io_common - sha256: "2ab92f8ff3ebbd4b353bf4a98bee45cc157e3255464b2f90f66e09c4472047eb" - url: "https://pub.dev" - source: hosted - version: "2.0.3" source_span: dependency: transitive description: @@ -497,18 +537,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -529,10 +569,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" timezone: dependency: transitive description: @@ -553,26 +593,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.4" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: c0766a55ab42cefaa728cabc951e82919ab41a3a4fee0aaa96176ca82da8cc51 + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.2" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "46b81e3109cbb2d6b81702ad3077540789a3e74e22795eb9f0b7d494dbaa72ea" + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.2.4" url_launcher_linux: dependency: transitive description: @@ -593,10 +633,10 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4aca1e060978e19b2998ee28503f40b5ba6226819c2b5e3e4d1821e8ccd92198" + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" url_launcher_web: dependency: transitive description: @@ -621,14 +661,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - web: + vm_service: dependency: transitive description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "2.4.0" win32: dependency: transitive description: @@ -662,5 +710,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index e0f1b337..272b40ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,10 +16,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 3.2.2+12 +version: 3.3.3+14 environment: - sdk: '>=2.19.0-429.0.dev <3.0.0' + sdk: '>=3.1.3 <4.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -46,12 +46,14 @@ dependencies: flutter_local_notifications: ^16.3.0 url_launcher: ^6.1.7 flutter_launcher_icons: ^0.13.1 - socket_io_client: ^2.0.1 flutter_bloc: ^8.1.3 equatable: ^2.0.5 hive: ^2.2.3 hive_flutter: ^1.1.0 http: ^1.1.0 + web_socket_channel: ^2.4.0 + package_info_plus: ^4.2.0 + firebase_remote_config: ^4.3.8 dev_dependencies: @@ -85,7 +87,7 @@ flutter: # To add assets to your application, add an assets section, like this: - # An image asset can refer to one or more resolution-specific "variants", see + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware # For details regarding adding assets from package dependencies, see