From 69daa4b95062b6d5ed4d37be0df14a33bd5c195f Mon Sep 17 00:00:00 2001 From: Armand <4831c0@proton.me> Date: Thu, 7 Aug 2025 18:04:55 +0200 Subject: [PATCH] remove WearOS from mobile app --- .gitmodules | 3 - .../kotlin/app/firka/naplo/MainActivity.kt | 76 ---- .../integration_test/wear_main_home_test.dart | 43 -- .../wear_main_login_test.dart | 24 -- firka/lib/main.dart | 21 +- .../lib/ui/wear/screens/home/home_screen.dart | 366 ------------------ .../ui/wear/screens/login/login_screen.dart | 278 ------------- .../widgets/circular_progress_indicator.dart | 115 ------ firka/lib/wear_main.dart | 180 --------- firka/pubspec.yaml | 2 - firka/vendor/wear_plus | 1 - 11 files changed, 6 insertions(+), 1103 deletions(-) delete mode 100644 firka/integration_test/wear_main_home_test.dart delete mode 100644 firka/integration_test/wear_main_login_test.dart delete mode 100644 firka/lib/ui/wear/screens/home/home_screen.dart delete mode 100644 firka/lib/ui/wear/screens/login/login_screen.dart delete mode 100644 firka/lib/ui/wear/widgets/circular_progress_indicator.dart delete mode 100644 firka/lib/wear_main.dart delete mode 160000 firka/vendor/wear_plus diff --git a/.gitmodules b/.gitmodules index 5cede1f..4aa91bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "firka/vendor/isar_flutter_libs"] path = firka/vendor/isar_flutter_libs url = https://git.qwit.cloud/firka/isar_flutter_libs -[submodule "firka/vendor/wear_plus"] - path = firka/vendor/wear_plus - url = https://git.qwit.cloud/firka/wear_plus [submodule "firka/lib/l10n"] path = firka/lib/l10n url = https://github.com/QwIT-Development/firka-localization diff --git a/firka/android/app/src/main/kotlin/app/firka/naplo/MainActivity.kt b/firka/android/app/src/main/kotlin/app/firka/naplo/MainActivity.kt index 38e39fa..382b197 100644 --- a/firka/android/app/src/main/kotlin/app/firka/naplo/MainActivity.kt +++ b/firka/android/app/src/main/kotlin/app/firka/naplo/MainActivity.kt @@ -1,86 +1,10 @@ package app.firka.naplo -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.content.Context -import android.content.pm.PackageManager import android.os.Bundle -import androidx.core.app.NotificationCompat -import androidx.wear.ongoing.OngoingActivity -import androidx.wear.ongoing.Status import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.MethodChannel - class MainActivity : FlutterActivity() { - private val channel = "firka.app/main" - private val channelId = "ongoing_activity" - private val notificationId = 1000 - - override fun configureFlutterEngine(flutterEngine: FlutterEngine) { - val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) - as NotificationManager - - notificationManager.createNotificationChannel( - NotificationChannel( - channelId, - "Ongoing Activity", - NotificationManager.IMPORTANCE_DEFAULT - ) - ) - - val notificationBuilder = NotificationCompat.Builder(this, channelId) - .setSmallIcon(R.drawable.ic_notification) - .setOngoing(true) - - val ongoingActivityStatus = Status.Builder() - // Sets the text used across various surfaces. - .addTemplate("Firka") - .build() - - val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)!! - val activityPendingIntent = PendingIntent.getActivity( - context, - 0, - intent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - - val ongoingActivity = OngoingActivity.Builder(applicationContext, - notificationId, notificationBuilder) - .setStaticIcon(R.drawable.ic_notification) - .setTouchIntent(activityPendingIntent) - .setStatus(ongoingActivityStatus) - .build() - - ongoingActivity.apply(applicationContext) - - - super.configureFlutterEngine(flutterEngine) - MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { - call, result -> - when (call.method) { - "isWear" -> { - result.success(packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) - } - "activity_update" -> { - notificationManager.notify(notificationId, notificationBuilder.build()) - result.success(null) - } - "activity_cancel" -> { - notificationManager.cancel(notificationId) - result.success(null) - } - else -> { - result.notImplemented() - } - } - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_SECURE) diff --git a/firka/integration_test/wear_main_home_test.dart b/firka/integration_test/wear_main_home_test.dart deleted file mode 100644 index f91ec09..0000000 --- a/firka/integration_test/wear_main_home_test.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:firka/helpers/db/models/generic_cache_model.dart'; -import 'package:firka/helpers/db/models/timetable_cache_model.dart'; -import 'package:firka/helpers/db/models/token_model.dart'; -import 'package:firka/wear_main.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; -import 'package:isar/isar.dart'; -import 'package:path_provider/path_provider.dart'; - -import 'test_helpers.dart'; - -Future main() async { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - await resetAppData(); - setApiUrls(); - - group('main', () { - testWidgets('WearInitializationScreen -> WearHomeScreen', (tester) async { - final dir = await getApplicationDocumentsDirectory(); - - var isar = await Isar.open( - [TokenModelSchema, GenericCacheModelSchema, TimetableCacheModelSchema], - inspector: true, - directory: dir.path, - ); - - isarInit = isar; - - await isar.writeTxn(() async { - await isar.tokenModels.put(TokenModel()); - }); - - await tester.pumpWidget(WearInitializationScreen()); - - await waitUntil(Duration(minutes: 2), tester, () async { - var ele = find.byKey(const Key('wearHomeScreen')); - return ele.allCandidates.isNotEmpty; - }); - }); - }); -} diff --git a/firka/integration_test/wear_main_login_test.dart b/firka/integration_test/wear_main_login_test.dart deleted file mode 100644 index 5cdbe7a..0000000 --- a/firka/integration_test/wear_main_login_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:firka/wear_main.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'test_helpers.dart'; - -Future main() async { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - await resetAppData(); - setApiUrls(); - - group('main', () { - testWidgets('WearInitializationScreen -> LoginScreen', (tester) async { - await tester.pumpWidget(WearInitializationScreen()); - - await waitUntil(Duration(minutes: 2), tester, () async { - var ele = find.byKey(const Key('wearLoginScreen')); - return ele.allCandidates.isNotEmpty; - }); - }); - }); -} diff --git a/firka/lib/main.dart b/firka/lib/main.dart index 25e02d8..4bab6c7 100644 --- a/firka/lib/main.dart +++ b/firka/lib/main.dart @@ -13,7 +13,6 @@ import 'package:firka/ui/phone/screens/debug/debug_screen.dart'; import 'package:firka/ui/phone/screens/home/home_screen.dart'; import 'package:firka/ui/phone/screens/login/login_screen.dart'; import 'package:firka/ui/phone/screens/wear_login/wear_login_screen.dart'; -import 'package:firka/wear_main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -100,7 +99,8 @@ Future initializeApp() async { KretaEndpoints.kretaBase = "https://$host"; KretaEndpoints.kretaIdp = KretaEndpoints.kretaBase; KretaEndpoints.kretaLoginUrl = - "${KretaEndpoints.kretaBase}/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fprompt%3Dlogin%26nonce%3DwylCrqT4oN6PPgQn2yQB0euKei9nJeZ6_ffJ-VpSKZU%26response_type%3Dcode%26code_challenge_method%3DS256%26scope%3Dopenid%2520email%2520offline_access%2520kreta-ellenorzo-webapi.public%2520kreta-eugyintezes-webapi.public%2520kreta-fileservice-webapi.public%2520kreta-mobile-global-webapi.public%2520kreta-dkt-webapi.public%2520kreta-ier-webapi.public%26code_challenge%3DHByZRRnPGb-Ko_wTI7ibIba1HQ6lor0ws4bcgReuYSQ%26redirect_uri%3Dhttps%253A%252F%252Fmobil.e-kreta.hu%252Fellenorzo-student%252Fprod%252Foauthredirect%26client_id%3Dkreta-ellenorzo-student-mobile-ios%26state%3Dkreta_student_mobile%26suppressed_prompt%3Dlogin"; + "${KretaEndpoints + .kretaBase}/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fprompt%3Dlogin%26nonce%3DwylCrqT4oN6PPgQn2yQB0euKei9nJeZ6_ffJ-VpSKZU%26response_type%3Dcode%26code_challenge_method%3DS256%26scope%3Dopenid%2520email%2520offline_access%2520kreta-ellenorzo-webapi.public%2520kreta-eugyintezes-webapi.public%2520kreta-fileservice-webapi.public%2520kreta-mobile-global-webapi.public%2520kreta-dkt-webapi.public%2520kreta-ier-webapi.public%26code_challenge%3DHByZRRnPGb-Ko_wTI7ibIba1HQ6lor0ws4bcgReuYSQ%26redirect_uri%3Dhttps%253A%252F%252Fmobil.e-kreta.hu%252Fellenorzo-student%252Fprod%252Foauthredirect%26client_id%3Dkreta-ellenorzo-student-mobile-ios%26state%3Dkreta_student_mobile%26suppressed_prompt%3Dlogin"; KretaEndpoints.tokenGrantUrl = "${KretaEndpoints.kretaBase}/connect/token"; } @@ -133,17 +133,6 @@ void main() async { dio.options.connectTimeout = Duration(seconds: 5); dio.options.receiveTimeout = Duration(seconds: 3); - WidgetsFlutterBinding.ensureInitialized(); - const platform = MethodChannel('firka.app/main'); - if (Platform.isAndroid) { - var isWear = (await platform.invokeMethod("isWear")) as bool; - - if (isWear) { - wearMain(platform); - return; - } - } - runZonedGuarded(() async { WidgetsFlutterBinding.ensureInitialized(); @@ -249,11 +238,13 @@ class InitializationScreen extends StatelessWidget { supportedLocales: AppLocalizations.supportedLocales, home: screen, routes: { - '/login': (context) => LoginScreen( + '/login': (context) => + LoginScreen( initData, key: ValueKey('loginScreen'), ), - '/debug': (context) => DebugScreen( + '/debug': (context) => + DebugScreen( initData, key: ValueKey('debugScreen'), ), diff --git a/firka/lib/ui/wear/screens/home/home_screen.dart b/firka/lib/ui/wear/screens/home/home_screen.dart deleted file mode 100644 index 728a5a2..0000000 --- a/firka/lib/ui/wear/screens/home/home_screen.dart +++ /dev/null @@ -1,366 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:firka/helpers/api/model/timetable.dart'; -import 'package:firka/helpers/extensions.dart'; -import 'package:firka/ui/widget/class_icon.dart'; -import 'package:firka/wear_main.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_arc_text/flutter_arc_text.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:zear_plus/wear_plus.dart'; - -import '../../../../helpers/debug_helper.dart'; -import '../../../../l10n/app_localizations.dart'; -import '../../../model/style.dart'; -import '../../widgets/circular_progress_indicator.dart'; - -class WearHomeScreen extends StatefulWidget { - final WearAppInitialization data; - - const WearHomeScreen(this.data, {super.key}); - - @override - State createState() => _WearHomeScreenState(data); -} - -class _WearHomeScreenState extends State { - final WearAppInitialization data; - - _WearHomeScreenState(this.data); - - int? currentLessonNo; - List today = List.empty(growable: true); - String apiError = ""; - DateTime now = timeNow(); - Timer? timer; - bool init = false; - WearMode mode = WearMode.active; - final platform = MethodChannel('firka.app/main'); - - bool disposed = false; - - @override - void initState() { - super.initState(); - now = timeNow(); - - timer = Timer.periodic(Duration(seconds: 1), (timer) async { - setState(() { - now = timeNow(); - }); - }); - initStateAsync(); - } - - Future initStateAsync() async { - var kreta = data.client; - - now = timeNow(); - var todayStart = now.getMidnight(); - var todayEnd = todayStart.add(Duration(hours: 23, minutes: 59)); - var classes = await kreta.getTimeTable(todayStart, todayEnd); - - if (disposed) return; - setState(() { - if (classes.response != null) today = classes.response!; - if (classes.statusCode != 200) { - apiError = "Unexpected status : ${classes.statusCode}"; - } - if (classes.err != null) apiError = classes.err!; - - init = true; - }); - } - - (List, double) buildBody(BuildContext context, WearMode mode) { - ScreenUtil.init(context); - - var body = List.empty(growable: true); - if (!init) { - return (body, 255.h); - } - - if (today.isEmpty && apiError != "") { - body.add(Text( - apiError, - style: - wearStyle.fonts.H_18px.apply(color: wearStyle.colors.textPrimary), - textAlign: TextAlign.center, - )); - - return (body, 255.h); - } - if (today.isEmpty) { - body.add(Text( - AppLocalizations.of(context)!.noClasses, - style: - wearStyle.fonts.H_18px.apply(color: wearStyle.colors.textPrimary), - textAlign: TextAlign.center, - )); - - platform.invokeMethod('activity_cancel'); - return (body, 255.h); - } - if (now.isAfter(today.last.end)) { - body.add(Text( - AppLocalizations.of(context)!.noMoreClasses, - style: - wearStyle.fonts.H_18px.apply(color: wearStyle.colors.textPrimary), - textAlign: TextAlign.center, - )); - - platform.invokeMethod('activity_cancel'); - return (body, 300.h); - } - if (now.isBefore(today.first.start)) { - var untilFirst = today.first.start.difference(now); - - body.add(Text( - AppLocalizations.of(context)!.firstIn(untilFirst.formatDuration()), - style: - wearStyle.fonts.H_18px.apply(color: wearStyle.colors.textPrimary), - textAlign: TextAlign.center, - )); - - platform.invokeMethod('activity_update'); - return (body, 255.h); - } - currentLessonNo = null; - if (now.isAfter(today.first.start) && now.isBefore(today.last.end)) { - Lesson? currentLesson = today.getCurrentLesson(now); - Lesson? lastLesson = today.getPrevLesson(now); - Lesson? nextLesson = today.getNextLesson(now); - - if (currentLesson != null) { - currentLessonNo = today.getLessonNo(currentLesson); - } - - Duration? currentBreak; - Duration? currentBreakProgress; - - if (lastLesson != null && nextLesson != null) { - currentBreak = nextLesson.start.difference(lastLesson.end); - currentBreakProgress = nextLesson.start.difference(now); - } - - if (currentLesson == null) { - if (currentBreak == null) { - throw Exception("currentBreak == null"); - } - if (currentBreakProgress == null) { - throw Exception("currentBreakProgress == null"); - } - - var minutes = currentBreakProgress.inMinutes + 1; - - body.add(CustomPaint( - painter: CircularProgressPainter( - progress: currentBreakProgress.inMilliseconds / - currentBreak.inMilliseconds, - // progress: 5 / 10, - screenSize: MediaQuery.of(context).size, - strokeWidth: 4, - color: wearStyle.colors.accent), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: 55.h), - Center( - child: Text( - AppLocalizations.of(context)!.breakTxt, - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 14, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 600), - ], - ), - ), - ), - Center( - child: Text( - AppLocalizations.of(context)!.timeLeft(minutes), - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 12, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 400), - ], - ), - ), - ) - ], - ))); - - platform.invokeMethod('activity_update'); - return (body, 200.h); - } else { - var duration = currentLesson.start.difference(currentLesson.end); - var elapsed = currentLesson.start.difference(now); - var timeLeft = currentLesson.end.difference(now); - - var minutes = timeLeft.inMinutes + 1; - - Widget nextLessonWidget = SizedBox(); - - if (nextLesson != null) { - nextLessonWidget = Center( - child: Text( - "→ ${nextLesson.name}, ${nextLesson.roomName}", - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 12, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 400), - ], - ), - ), - ); - } - - body.add(CustomPaint( - painter: CircularProgressPainter( - progress: elapsed.inMilliseconds / duration.inMilliseconds, - screenSize: MediaQuery.of(context).size, - strokeWidth: 4, - color: wearStyle.colors.accent), - child: Column(children: [ - SizedBox(height: nextLesson == null ? 20.h : 0), - Center( - child: ClassIconWidget( - color: wearStyle.colors.accent, - size: 16, - uid: currentLesson.uid, - className: currentLesson.name, - category: currentLesson.subject?.name ?? '', - ).build(context), - ), - const SizedBox(height: 4), - Center( - child: Text( - "${currentLesson.name}, ${currentLesson.roomName}", - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 14, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 600), - ], - ), - ), - ), - Center( - child: Text( - AppLocalizations.of(context)!.timeLeft(minutes), - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 12, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 400), - ], - ), - ), - ), - const SizedBox(height: 8), - nextLessonWidget, - ]))); - - platform.invokeMethod('activity_update'); - return (body, 200.h); - } - } - - platform.invokeMethod('activity_cancel'); - throw Exception("unexpected state"); - } - - @override - Widget build(BuildContext context) { - Widget titleBar = SizedBox(); - - if (currentLessonNo != null) { - titleBar = ArcText( - radius: 99, - startAngle: pi / 180, - startAngleAlignment: StartAngleAlignment.center, - text: AppLocalizations.of(context)!.wearTitle(currentLessonNo!), - textStyle: TextStyle( - fontSize: 12, - color: wearStyle.colors.secondary, - fontFamily: 'Montserrat', - fontVariations: [ - FontVariation('wght', 500), - ], - ), - placement: Placement.inside, - ); - } - - return Scaffold( - backgroundColor: mode == WearMode.active - ? wearStyle.colors.background - : wearStyle.colors.backgroundAmoled, - body: Stack( - children: [ - Center( - child: titleBar, - ), - Center( - child: Column( - children: [ - WatchShape( - builder: (context, shape, child) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - child!, - ], - ); - }, - child: AmbientMode( - builder: (context, mode, child) { - if (this.mode != mode) { - Timer(Duration(milliseconds: 100), () { - setState(() { - this.mode = mode; - }); - }); - } - - var (body, padding) = buildBody(context, mode); - - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: padding), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [...body], - )), - ], - ); - }, - ), - ) - ], - ), - ) - ], - ), - ); - } - - @override - void dispose() { - super.dispose(); - timer?.cancel(); - disposed = true; - } -} diff --git a/firka/lib/ui/wear/screens/login/login_screen.dart b/firka/lib/ui/wear/screens/login/login_screen.dart deleted file mode 100644 index d5c4e80..0000000 --- a/firka/lib/ui/wear/screens/login/login_screen.dart +++ /dev/null @@ -1,278 +0,0 @@ -// ignore_for_file: avoid_print - -import 'dart:async'; - -import 'package:firka/helpers/api/client/kreta_client.dart'; -import 'package:firka/helpers/extensions.dart'; -import 'package:flutter/material.dart'; -import 'package:watch_connectivity/watch_connectivity.dart'; -import 'package:zear_plus/wear_plus.dart'; - -import '../../../../helpers/db/models/token_model.dart'; -import '../../../../wear_main.dart'; -import '../../../model/style.dart'; -import '../home/home_screen.dart'; - -class WearLoginScreen extends StatefulWidget { - final WearAppInitialization data; - const WearLoginScreen(this.data, {super.key}); - - @override - State createState() => _WearLoginScreen(data); -} - -class _WearLoginScreen extends State { - final WearAppInitialization initData; - _WearLoginScreen(this.initData); - - bool init = false; - bool isPaired = false; - bool isReachable = false; - bool isMessageSending = false; - bool isMessageSent = false; - final watch = WatchConnectivity(); - late Timer connectionTimer; - - @override - void initState() { - super.initState(); - - watch.messageStream.listen((e) { - var msg = e.entries.toMap(); - var id = msg["id"]; - - debugPrint("[Phone -> Watch]: $id"); - - switch (id) { - case "pong": - { - setState(() { - isMessageSent = true; - }); - } - case "auth": - { - () async { - var data = msg["data"]; - var tokenModel = TokenModel.fromValues( - data["studentId"], - data["iss"], - data["idToken"], - data["accessToken"], - data["refreshToken"], - data["expiryDate"]); - - initData.client = KretaClient(tokenModel, initData.isar); - - await initData.isar.writeTxn(() async { - await initData.isar.tokenModels.put(tokenModel); - }); - - Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute( - builder: (context) => WearHomeScreen(initData)), - (route) => false, // Remove all previous routes - ); - }(); - } - } - }); - - connectionTimer = Timer.periodic(Duration(seconds: 1), (timer) async { - var p = await watch.isPaired; - var r = await watch.isReachable; - - if (!isMessageSending) { - isMessageSending = true; - - debugPrint("[Watch -> Phone]: ping"); - watch.sendMessage({'id': 'ping'}); - } - - setState(() { - init = true; - isPaired = p; - isReachable = r; - }); - }); - } - - (List, double) buildBody(BuildContext context) { - if (!init) { - return ( - [ - Text( - "Loading...", - textAlign: TextAlign.center, - style: wearStyle.fonts.H_18px - .apply(color: wearStyle.colors.textPrimary), - ), - ], - 65 - ); - } - - if (!isPaired) { - return ( - [ - Text( - "Watch not paired with your phone", - textAlign: TextAlign.center, - style: wearStyle.fonts.H_18px - .apply(color: wearStyle.colors.textPrimary), - ), - ], - 65 - ); - } - if (!isReachable) { - return ( - [ - Text( - "Watch not connected\n to your phone", - textAlign: TextAlign.center, - style: wearStyle.fonts.H_18px - .apply(color: wearStyle.colors.textPrimary), - ), - ], - 65 - ); - } - - if (!isMessageSent && isMessageSending) { - return ( - [ - Text( - "Sending request...", - textAlign: TextAlign.center, - style: wearStyle.fonts.H_18px - .apply(color: wearStyle.colors.textPrimary), - ), - ElevatedButton( - onPressed: () async { - debugPrint("[Watch -> Phone]: ping"); - watch.sendMessage({'id': 'ping'}); - }, - // TODO: This is a placeholder, style this properly - style: ButtonStyle( - backgroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.pressed)) { - return wearStyle.colors.accent; - } - return wearStyle.colors.accent; - }), - foregroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.pressed)) { - return wearStyle.colors.accent; - } - return wearStyle.colors.accent; - }), - ), - child: Text('Try again', - textAlign: TextAlign.center, - style: TextStyle(color: wearStyle.colors.textPrimary)), - ), - ], - 45 - ); - } - - if (isMessageSent) { - return ( - [ - Text( - "Check your phone!", - textAlign: TextAlign.center, - style: wearStyle.fonts.H_18px - .apply(color: wearStyle.colors.textPrimary), - ), - ElevatedButton( - onPressed: () async { - debugPrint("[Watch -> Phone]: ping"); - watch.sendMessage({'id': 'ping'}); - }, - // TODO: This is a placeholder, style this properly - style: ButtonStyle( - backgroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.pressed)) { - return wearStyle.colors.accent; - } - return wearStyle.colors.accent; - }), - foregroundColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.pressed)) { - return wearStyle.colors.accent; - } - return wearStyle.colors.accent; - }), - ), - child: Text('Try again', - textAlign: TextAlign.center, - style: TextStyle(color: wearStyle.colors.textPrimary)), - ), - ], - 45 - ); - } - - return ( - [ - Text("Unexpected state", - style: TextStyle(color: wearStyle.colors.textPrimary, fontSize: 18), - textAlign: TextAlign.center), - ], - 65 - ); - } - - @override - Widget build(BuildContext context) { - var (body, offset) = buildBody(context); - - return Scaffold( - backgroundColor: wearStyle.colors.background, - body: Center( - child: Column( - children: [ - WatchShape( - builder: (context, shape, child) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Login", - textAlign: TextAlign.center, - style: TextStyle( - color: wearStyle.colors.textPrimary, - fontSize: 20, - fontWeight: FontWeight.w500, - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(top: offset), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: body, - )), - ], - ), - child!, - ], - ); - }, - child: SizedBox()) - ], - ), - ), - ); - } - - @override - void dispose() { - super.dispose(); - connectionTimer.cancel(); - } -} diff --git a/firka/lib/ui/wear/widgets/circular_progress_indicator.dart b/firka/lib/ui/wear/widgets/circular_progress_indicator.dart deleted file mode 100644 index 075b49e..0000000 --- a/firka/lib/ui/wear/widgets/circular_progress_indicator.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; - -class CircularProgressIndicatorWidget extends StatefulWidget { - final double progress; - final double strokeWidth; - final Color color; - final Size screenSize; - - const CircularProgressIndicatorWidget({ - super.key, - required this.progress, - required this.screenSize, - this.strokeWidth = 8.0, - required this.color, - }); - - @override - _CircularProgressIndicatorWidgetState createState() => - _CircularProgressIndicatorWidgetState(); -} - -class _CircularProgressIndicatorWidgetState - extends State - with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _animation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 500), - vsync: this, - ); - _animation = - Tween(begin: 0.0, end: widget.progress).animate(_controller); - _controller.forward(); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return CustomPaint( - painter: CircularProgressPainter( - progress: _animation.value, - strokeWidth: widget.strokeWidth, - color: widget.color, - screenSize: widget.screenSize, - ), - child: SizedBox.expand(), // Fill the entire screen - ); - }, - ); - } -} - -class CircularProgressPainter extends CustomPainter { - final double progress; - final double strokeWidth; - final Color color; - final Size screenSize; - - CircularProgressPainter({ - required this.progress, - required this.strokeWidth, - required this.color, - required this.screenSize, - }); - - @override - void paint(Canvas canvas, Size size) { - final center = Offset(screenSize.width / 2, screenSize.height / 4.7); - final radius = - min(screenSize.width, screenSize.height) / 2 - strokeWidth / 2; - final startAngle = -pi / 2; - var sweepAngle = 2 * pi * progress; - - final paint = Paint() - ..color = color - ..style = PaintingStyle.stroke - ..strokeWidth = strokeWidth; - - if (sweepAngle >= 6) { - sweepAngle -= 0.6; - } else { - sweepAngle -= 0.35; - - if (sweepAngle > 5.4) sweepAngle = 5.4; - } - if (sweepAngle <= 0) sweepAngle = 0; - - canvas.drawArc( - Rect.fromCircle(center: center, radius: radius), - startAngle + 0.3, - sweepAngle, - false, - paint, - ); - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return true; - } -} diff --git a/firka/lib/wear_main.dart b/firka/lib/wear_main.dart deleted file mode 100644 index b7d5b80..0000000 --- a/firka/lib/wear_main.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:firka/helpers/db/models/generic_cache_model.dart'; -import 'package:firka/helpers/db/models/homework_cache_model.dart'; -import 'package:firka/helpers/db/models/timetable_cache_model.dart'; -import 'package:firka/helpers/db/models/token_model.dart'; -import 'package:firka/ui/wear/screens/login/login_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:isar/isar.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:zear_plus/wear_plus.dart'; - -import 'helpers/api/client/kreta_client.dart'; -import 'l10n/app_localizations.dart'; -import 'ui/wear/screens/home/home_screen.dart'; - -Isar? isarInit; -final GlobalKey navigatorKey = GlobalKey(); - -class WearAppInitialization { - final Isar isar; - late KretaClient client; - final int tokenCount; - - WearAppInitialization({required this.isar, required this.tokenCount}); -} - -Future initDB() async { - if (isarInit != null) return isarInit!; - final dir = await getApplicationDocumentsDirectory(); - - isarInit = await Isar.open( - [ - TokenModelSchema, - GenericCacheModelSchema, - TimetableCacheModelSchema, - HomeworkCacheModelSchema - ], - inspector: true, - directory: dir.path, - ); - - return isarInit!; -} - -Future initializeApp() async { - final isar = await initDB(); - - var init = WearAppInitialization( - isar: isar, tokenCount: await isar.tokenModels.count()); - - resetOldTimeTableCache(isar); - resetOldHomeworkCache(isar); - - // TODO: Account selection - if (init.tokenCount > 0) { - init.client = - KretaClient((await isar.tokenModels.where().findFirst())!, isar); - } - - return init; -} - -void wearMain(MethodChannel platform) async { - WidgetsFlutterBinding.ensureInitialized(); - - if (await Permission.notification.isDenied) { - var status = await Permission.notification.request(); - - if (status.isDenied) { - exit(-1); - } - } - - await ScreenUtil.ensureScreenSize(); - - // Run App Initialization - runApp(WearInitializationScreen()); -} - -class WearInitializationScreen extends StatelessWidget { - WearInitializationScreen({super.key}); - - // Place to store the initialization future - final Future _initialization = initializeApp(); - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: _initialization, - builder: (context, snapshot) { - // Check if initialization is complete - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { - // Handle initialization error - - return MaterialApp( - key: ValueKey('firkaErrorPage'), - home: Scaffold( - body: Center( - child: WatchShape( - builder: (context, shape, child) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Error initializing app: ${snapshot.error}', - style: TextStyle(color: Colors.red), - ), - child!, - ], - ); - }, - child: SizedBox(), - ), - ), - ), - ); - } - - // Initialization successful, determine which screen to show - Widget screen; - - assert(snapshot.data != null); - var data = snapshot.data!; - - if (snapshot.data!.tokenCount == 0) { - screen = WearLoginScreen(data, key: ValueKey('wearLoginScreen')); - } else { - screen = WearHomeScreen(data, key: ValueKey('wearHomeScreen')); - } - - return MaterialApp( - key: ValueKey('firkaWearApp'), - title: 'Firka', - navigatorKey: navigatorKey, - // Use the global navigator key - theme: ThemeData( - primarySwatch: Colors.lightGreen, - visualDensity: VisualDensity.adaptivePlatformDensity, - ), - localizationsDelegates: [ - AppLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: AppLocalizations.supportedLocales, - home: screen, - routes: { - '/login': (context) => - WearLoginScreen(data, key: ValueKey('wearLoginScreen')), - '/home': (context) => - WearHomeScreen(data, key: ValueKey('wearHomeScreen')) - }, - ); - } - - return MaterialApp( - home: Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - color: const Color(0xFF7CA021), - ) - ], - ), - ), - ), - ); - }, - ); - } -} diff --git a/firka/pubspec.yaml b/firka/pubspec.yaml index 2c76620..c558c3e 100644 --- a/firka/pubspec.yaml +++ b/firka/pubspec.yaml @@ -46,8 +46,6 @@ dependencies: carousel_slider: ^5.0.0 webview_flutter: ^4.7.0 dart_jsonwebtoken: ^3.2.0 - zear_plus: - path: vendor/wear_plus majesticons_flutter: ^0.0.1 watch_connectivity: ^0.2.1+1 permission_handler: ^11.4.0 diff --git a/firka/vendor/wear_plus b/firka/vendor/wear_plus deleted file mode 160000 index a6fb67b..0000000 --- a/firka/vendor/wear_plus +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a6fb67b23edea4b2657bbd0cbb7150de85b88db6