commit 2a2f718a4b18ec47801aaa53551dce83ec7ef079 Author: Developer Date: Fri Jan 9 00:20:38 2026 +0800 Initial commit: Minimal Flutter timer with push notifications diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45371f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# Flutter +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +build/ + +# Android +android/.gradle/ +android/local.properties +android/*.iml +android/.idea/ +android/.settings/ +android/build/ +android/app/build/ +android/app/release/ +android/app/debug/ + +# iOS +ios/Pods/ +ios/Podfile.lock +ios/.symlinks/ +ios/Flutter/Flutter.framework +ios/Flutter/Flutter.podspec +ios/Flutter/generated.xcconfig +ios/Flutter/app.flx +ios/Flutter/app.zip + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log + +# Test +coverage/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..db96fac --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Минимальный Таймер на Flutter + +Минималистичное приложение таймера для Android с push-уведомлениями. + +## Запуск + +1. Установите Flutter SDK (3.0+) +2. Клонируйте репозиторий +3. Выполните команды: + +```bash +cd minimal_timer +flutter pub get +flutter run +``` + +## Функции + +- Таймер обратного отсчёта +- Визуальный прогресс-бар +- Push-уведомление по завершении +- Material Design 3 +- Минимальный код (~150 строк) + +## Настройка Android + +Приложение требует Android SDK 34+. Минимальная версия Android — 21. + +## Разрешения + +- `POST_NOTIFICATIONS` — отправка уведомлений +- `VIBRATE` — вибрация при уведомлении +- `RECEIVE_BOOT_COMPLETED` — восстановление после перезагрузки diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..4e8616a --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,5 @@ +linter: + rules: + - prefer_const_constructors + - prefer_const_declarations + - avoid_print diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..c2651d9 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,65 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +def javaVersion = JavaVersion.VERSION_17 + +android { + namespace "com.example.timer" + compileSdk 34 + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility javaVersion + targetCompatibility javaVersion + } + + kotlinOptions { + jvmTarget = javaVersion.toString() + } + + sourceSets { + main.java.srcDirs += 'src/main/java' + } + + defaultConfig { + applicationId "com.example.timer" + minSdkVersion flutter.minSdkVersion + targetSdk 34 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6ae8130 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/java/com/example/timer/MainActivity.java b/android/app/src/main/java/com/example/timer/MainActivity.java new file mode 100644 index 0000000..6b61753 --- /dev/null +++ b/android/app/src/main/java/com/example/timer/MainActivity.java @@ -0,0 +1,24 @@ +package com.example.timer; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Launch Flutter activity using reflection + try { + Class flutterActivityClass = Class.forName("io.flutter.embedding.android.FlutterActivity"); + Intent intent = new Intent(this, flutterActivityClass); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } catch (ClassNotFoundException e) { + // FlutterActivity not found - handle gracefully + e.printStackTrace(); + } + finish(); + } +} diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..eaa58c3 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..0fde76c --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.xml b/android/app/src/main/res/mipmap-hdpi/ic_launcher.xml new file mode 100644 index 0000000..a08cae9 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.xml b/android/app/src/main/res/mipmap-mdpi/ic_launcher.xml new file mode 100644 index 0000000..a08cae9 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.xml b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.xml new file mode 100644 index 0000000..a08cae9 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.xml b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.xml new file mode 100644 index 0000000..a08cae9 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.xml b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.xml new file mode 100644 index 0000000..a08cae9 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..1213228 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #6200EE + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..43dfcad --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..bd3a644 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,41 @@ +def flutterSdkPath = System.env.FLUTTER_SDK ?: System.properties['flutter.sdk'] + +buildscript { + ext.kotlin_version = '1.8.22' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.1.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} + +String flutterProjectRoot = rootProject.projectDir.parentFile.toPath().normalize().toString() + +File pluginsFile = new File(flutterProjectRoot, '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.text.eachLine { line -> + def pluginDef = line.split('=') + if (pluginDef.length == 2) { + def pluginName = pluginDef[0] + def pluginPath = pluginDef[1] + include ":$pluginName" + project(":$pluginName").projectDir = new File(pluginPath, 'android') + } + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..598d13f --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100755 index 0000000..13372ae Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..348c409 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 120000 index 0000000..d1ad565 --- /dev/null +++ b/android/gradlew @@ -0,0 +1 @@ +gradlew.bat \ No newline at end of file diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100755 index 0000000..aec9973 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/gradlew.sh b/android/gradlew.sh new file mode 100644 index 0000000..24c4073 --- /dev/null +++ b/android/gradlew.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" +export ANDROID_HOME=$HOME/android-sdk +export FLUTTER_SDK=$HOME/bin/flutter +exec /home/minimax/bin/jdk-17.0.17+10/bin/java -classpath gradle/wrapper/gradle-wrapper.jar org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..03cc4c1 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,26 @@ +pluginManagement { + def flutterSdkPath = System.env.FLUTTER_SDK ?: System.properties['flutter.sdk'] + assert flutterSdkPath != null, "FLUTTER_SDK not set. Run: export FLUTTER_SDK=/path/to/flutter" + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + google() + mavenCentral() + maven { + url "https://storage.googleapis.com/download.flutter.io" + } + } +} + +rootProject.name = 'minimal_timer' +include(':app') diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..5933751 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,156 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +final notifications = FlutterLocalNotificationsPlugin(); + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); + const settings = InitializationSettings(android: androidSettings); + await notifications.initialize(settings); + await notifications.resolvePlatformSpecificImplementation()?.requestNotificationsPermission(); + runApp(const TimerApp()); +} + +class TimerApp extends StatelessWidget { + const TimerApp({super.key}); + + @override + Widget build(BuildContext context) => MaterialApp( + theme: ThemeData(useMaterial3: true, colorScheme: ColorScheme.fromSeed( + seedColor: Colors.deepPurple, + brightness: Brightness.light, + )), + home: const TimerScreen(), + ); +} + +class TimerScreen extends StatefulWidget { + const TimerScreen({super.key}); + + @override + State createState() => _TimerScreenState(); +} + +class _TimerScreenState extends State { + int duration = 60; + int remaining = 60; + Timer? timer; + bool isRunning = false; + + void _showNotification() async { + const androidDetails = AndroidNotificationDetails( + 'timer_channel', + 'Таймер', + channelDescription: 'Уведомления таймера', + importance: Importance.high, + priority: Priority.high, + ); + const details = NotificationDetails(android: androidDetails); + await notifications.show(0, 'Таймер завершён!', 'Время вышло.', details); + } + + void _startTimer() { + setState(() => isRunning = true); + timer = Timer.periodic(const Duration(seconds: 1), (_) { + if (remaining > 0) { + setState(() => remaining--); + } else { + timer?.cancel(); + _showNotification(); + setState(() => isRunning = false); + } + }); + } + + void _pauseTimer() { + timer?.cancel(); + setState(() => isRunning = false); + } + + void _resetTimer() { + timer?.cancel(); + setState(() { + isRunning = false; + remaining = duration; + }); + } + + void _selectDuration() { + showModalBottomSheet( + context: context, + builder: (_) => Column( + mainAxisSize: MainAxisSize.min, + children: [1, 5, 10, 15, 30, 60].map((m) { + return ListTile( + title: Text('$m мин'), + onTap: () { + setState(() { + duration = m * 60; + remaining = duration; + }); + Navigator.pop(context); + }, + ); + }).toList(), + ), + ); + } + + @override + void dispose() { + timer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final minutes = (remaining / 60).floor(); + final seconds = remaining % 60; + final progress = duration > 0 ? (remaining / duration) as double : 0.0; + + return Scaffold( + appBar: AppBar(title: const Text('Таймер')), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: _selectDuration, + child: Stack( + alignment: Alignment.center, + children: [ + SizedBox( + width: 200, + height: 200, + child: CircularProgressIndicator( + value: progress, + strokeWidth: 8, + ), + ), + Text( + '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}', + style: Theme.of(context).textTheme.displayMedium, + ), + ], + ), + ), + const SizedBox(height: 40), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FloatingActionButton( + onPressed: isRunning ? _pauseTimer : _startTimer, + child: Icon(isRunning ? Icons.pause : Icons.play_arrow), + ), + if (remaining != duration) ...[ + const SizedBox(width: 16), + OutlinedButton(onPressed: _resetTimer, child: const Text('Сброс')), + ], + ], + ), + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..aff2739 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,354 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c + url: "https://pub.dev" + source: hosted + version: "2.1.5" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "55b9b229307a10974b26296ff29f2e132256ba4bd74266939118eaefa941cb00" + url: "https://pub.dev" + source: hosted + version: "16.3.3" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" + url: "https://pub.dev" + source: hosted + version: "7.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + 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: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + url: "https://pub.dev" + source: hosted + version: "0.7.7" + timezone: + dependency: transitive + description: + name: timezone + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.8.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..ca960d9 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,21 @@ +name: minimal_timer +description: Минималистичный таймер с уведомлениями +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + flutter_local_notifications: ^16.3.0 + permission_handler: ^11.1.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +flutter: + uses-material-design: true