Compare commits
37 Commits
d0b19a4975
...
local-noti
Author | SHA1 | Date | |
---|---|---|---|
98077e7d57 | |||
54d47245ae | |||
7f2cf0b49f | |||
8fe60e7ae3 | |||
b2e2eb67b0 | |||
0dc7c3ced0 | |||
13fe7e2ef4 | |||
d6e62024d7 | |||
4094f7edba | |||
586d2355c9 | |||
4e5eeec937 | |||
0c0f596fbb | |||
f781001d3b | |||
19f835d8f2 | |||
56b25a6963 | |||
5bae1aa416 | |||
29479e8aba | |||
9ffa0d178c | |||
932e9cd6a4 | |||
d42696df61 | |||
1564d6cd83 | |||
4fd36246ae | |||
e8e1737875 | |||
baa0f603cf | |||
d7bd755c57 | |||
8890346b59 | |||
a2812b40a0 | |||
1c8f03c97b | |||
b273979ac0 | |||
780e270c15 | |||
e3a09458d8 | |||
6b319a8d96 | |||
0fe3d65bb8 | |||
ec6381f04d | |||
88021cdade | |||
55a435718d | |||
df5f24ef16 |
145
.gitignore
vendored
@ -9,6 +9,7 @@
|
|||||||
.history
|
.history
|
||||||
.svn/
|
.svn/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
bkp
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
*.iml
|
*.iml
|
||||||
@ -31,6 +32,8 @@ migrate_working_dir/
|
|||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
pubspec.lock
|
||||||
|
devtools_options.yaml
|
||||||
|
|
||||||
# Symbolication related
|
# Symbolication related
|
||||||
app.*.symbols
|
app.*.symbols
|
||||||
@ -42,3 +45,145 @@ app.*.map.json
|
|||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
|
||||||
|
|
||||||
|
# Do not remove or rename entries in this file, only add new ones
|
||||||
|
# See https://github.com/flutter/flutter/issues/128635 for more context.
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.lock
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Visual Studio Code related
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
.vscode/*
|
||||||
|
|
||||||
|
# Flutter repo-specific
|
||||||
|
/bin/cache/
|
||||||
|
/bin/internal/bootstrap.bat
|
||||||
|
/bin/internal/bootstrap.sh
|
||||||
|
/bin/mingit/
|
||||||
|
/dev/benchmarks/mega_gallery/
|
||||||
|
/dev/bots/.recipe_deps
|
||||||
|
/dev/bots/android_tools/
|
||||||
|
/dev/devicelab/ABresults*.json
|
||||||
|
/dev/docs/doc/
|
||||||
|
/dev/docs/api_docs.zip
|
||||||
|
/dev/docs/flutter.docs.zip
|
||||||
|
/dev/docs/lib/
|
||||||
|
/dev/docs/pubspec.yaml
|
||||||
|
/dev/integration_tests/**/xcuserdata
|
||||||
|
/dev/integration_tests/**/Pods
|
||||||
|
/packages/flutter/coverage/
|
||||||
|
version
|
||||||
|
analysis_benchmark.json
|
||||||
|
|
||||||
|
# packages file containing multi-root paths
|
||||||
|
.packages.generated
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
**/generated_plugin_registrant.dart
|
||||||
|
.packages
|
||||||
|
.pub-preload-cache/
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
flutter_*.png
|
||||||
|
linked_*.ds
|
||||||
|
unlinked.ds
|
||||||
|
unlinked_spec.ds
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
.gradle/
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
**/android/key.properties
|
||||||
|
*.jks
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Flutter.podspec
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/ephemeral
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/Flutter/flutter_export_environment.sh
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
**/Flutter/ephemeral/
|
||||||
|
**/Pods/
|
||||||
|
**/macos/Flutter/GeneratedPluginRegistrant.swift
|
||||||
|
**/macos/Flutter/ephemeral
|
||||||
|
**/xcuserdata/
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
**/windows/flutter/ephemeral/
|
||||||
|
**/windows/flutter/generated_plugin_registrant.cc
|
||||||
|
**/windows/flutter/generated_plugin_registrant.h
|
||||||
|
**/windows/flutter/generated_plugins.cmake
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
**/linux/flutter/ephemeral/
|
||||||
|
**/linux/flutter/generated_plugin_registrant.cc
|
||||||
|
**/linux/flutter/generated_plugin_registrant.h
|
||||||
|
**/linux/flutter/generated_plugins.cmake
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# Symbols
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
!/dev/ci/**/Gemfile.lock
|
||||||
|
!.vscode/settings.json
|
34
.metadata
@ -1,11 +1,11 @@
|
|||||||
# This file tracks properties of this Flutter project.
|
# This file tracks properties of this Flutter project.
|
||||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
#
|
#
|
||||||
# This file should be version controlled.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
revision: "dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668"
|
||||||
channel: stable
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
|
||||||
@ -13,26 +13,26 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: android
|
- platform: android
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: ios
|
- platform: ios
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: linux
|
- platform: linux
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: macos
|
- platform: macos
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: web
|
- platform: web
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
- platform: windows
|
- platform: windows
|
||||||
create_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
create_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
base_revision: 9944297138845a94256f1cf37beb88ff9a8e811a
|
base_revision: dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
74
.vscode/dart.code-snippets
vendored
@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
// Place your snippets for dart here. Each snippet is defined under a snippet name and has a prefix, body and
|
|
||||||
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
|
||||||
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
|
|
||||||
// same ids are connected.
|
|
||||||
// Example:
|
|
||||||
// "Print to console": {
|
|
||||||
// "prefix": "log",
|
|
||||||
// "body": [
|
|
||||||
// "console.log('$1');",
|
|
||||||
// "$2"
|
|
||||||
// ],
|
|
||||||
// "description": "Log output to console"
|
|
||||||
// }
|
|
||||||
"Stateless Widget": {
|
|
||||||
"prefix": "stateless",
|
|
||||||
"body": [
|
|
||||||
"import 'package:flutter/material.dart';",
|
|
||||||
"\n",
|
|
||||||
"class ${1:MyClass} extends StatelessWidget {",
|
|
||||||
"@override",
|
|
||||||
"Widget build(BuildContext context) {",
|
|
||||||
"return Container($0);}}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Stateful Widget": {
|
|
||||||
"prefix": "stateful",
|
|
||||||
"body": [
|
|
||||||
"import 'package:flutter/material.dart';",
|
|
||||||
"\n",
|
|
||||||
"class ${1:MyClass} extends StatefulWidget {",
|
|
||||||
"const ${1:MyClass}({Key key, $2}) : super(key: key);",
|
|
||||||
"\n",
|
|
||||||
"@override",
|
|
||||||
"_${1:MyClass}State createState() => _${1:MyClass}State();",
|
|
||||||
"}",
|
|
||||||
"\n",
|
|
||||||
"class _${1:MyClass}State extends State<${1:MyClass}> {",
|
|
||||||
"\n",
|
|
||||||
"@override",
|
|
||||||
"void initState() {",
|
|
||||||
"super.initState();",
|
|
||||||
"}",
|
|
||||||
"\n",
|
|
||||||
"@override",
|
|
||||||
"void dispose() {",
|
|
||||||
"super.dispose();",
|
|
||||||
"}",
|
|
||||||
"\n",
|
|
||||||
"@override",
|
|
||||||
"Widget build(BuildContext context) {",
|
|
||||||
"return Container($0);}}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Widget Test": {
|
|
||||||
"prefix": "widgettest",
|
|
||||||
"body": [
|
|
||||||
"import 'package:flutter_test/flutter_test.dart';",
|
|
||||||
"import 'package:flutter/material.dart';",
|
|
||||||
"//import 'package:piota/${1:widgetfile}.dart';",
|
|
||||||
"\n",
|
|
||||||
"import 'ui_test_util.dart';",
|
|
||||||
"\n",
|
|
||||||
"void main() {",
|
|
||||||
"group('${2:groupname}', () {",
|
|
||||||
"final testableWidget = testWidget(${3:Container()},Size(375, 667));",
|
|
||||||
"testWidgets('${3:Container()} test', (WidgetTester tester) async {",
|
|
||||||
"final finder = find.byKey(Key('${5:keyname}'));",
|
|
||||||
"await tester.pumpWidget(testableWidget);",
|
|
||||||
"expect(finder, findsOneWidget);",
|
|
||||||
"});});}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
# SendTrain
|
# SendTrain v0.2.2
|
||||||
|
|
||||||
Mobile app for community driven climbing training and support.
|
Mobile app for community driven climbing training and support.
|
||||||
|
|
||||||
|
2
android/.gitignore
vendored
@ -7,7 +7,7 @@ gradle-wrapper.jar
|
|||||||
GeneratedPluginRegistrant.java
|
GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
# Remember to never publicly share your keystore.
|
||||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
# See https://flutter.dev/to/reference-keystore
|
||||||
key.properties
|
key.properties
|
||||||
**/*.keystore
|
**/*.keystore
|
||||||
**/*.jks
|
**/*.jks
|
||||||
|
@ -1,71 +1,44 @@
|
|||||||
def localProperties = new Properties()
|
plugins {
|
||||||
def localPropertiesFile = rootProject.file('local.properties')
|
id "com.android.application"
|
||||||
if (localPropertiesFile.exists()) {
|
id "kotlin-android"
|
||||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
localProperties.load(reader)
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
|
||||||
if (flutterRoot == null) {
|
|
||||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
|
||||||
if (flutterVersionCode == null) {
|
|
||||||
flutterVersionCode = '1'
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
|
||||||
if (flutterVersionName == null) {
|
|
||||||
flutterVersionName = '1.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion flutter.compileSdkVersion
|
namespace = "com.example.sendtrain"
|
||||||
ndkVersion flutter.ndkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_1_8
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.sendtrain.sendtrain"
|
applicationId = "com.example.sendtrain"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdkVersion 17
|
minSdk = flutter.minSdkVersion
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode = flutter.versionCode
|
||||||
versionName flutterVersionName
|
versionName = flutter.versionName
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig signingConfigs.debug
|
signingConfig = signingConfigs.debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source '../..'
|
source = "../.."
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
package="com.sendtrain.sendtrain">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
the Flutter tool needs it to communicate with the running application
|
the Flutter tool needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
package="com.sendtrain.sendtrain">
|
<application
|
||||||
<application
|
android:label="sendtrain"
|
||||||
android:label="SendTrain"
|
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:taskAffinity=""
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
@ -31,4 +31,15 @@
|
|||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
|
<!-- Required to query activities that can process text, see:
|
||||||
|
https://developer.android.com/training/package-visibility and
|
||||||
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
|
||||||
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
|
<data android:mimeType="text/plain"/>
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.sendtrain
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity()
|
@ -1,6 +0,0 @@
|
|||||||
package com.sendtrain.sendtrain
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
|
||||||
|
|
||||||
class MainActivity: FlutterActivity() {
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
package="com.sendtrain.sendtrain">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
the Flutter tool needs it to communicate with the running application
|
the Flutter tool needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
@ -1,16 +1,3 @@
|
|||||||
buildscript {
|
|
||||||
ext.kotlin_version = '1.7.10'
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
@ -18,14 +5,14 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.buildDir = '../build'
|
rootProject.buildDir = "../build"
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
}
|
}
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(":app")
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||||
|
@ -1,11 +1,25 @@
|
|||||||
include ':app'
|
pluginManagement {
|
||||||
|
def flutterSdkPath = {
|
||||||
|
def properties = new Properties()
|
||||||
|
file("local.properties").withInputStream { properties.load(it) }
|
||||||
|
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||||
|
return flutterSdkPath
|
||||||
|
}()
|
||||||
|
|
||||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
def properties = new Properties()
|
|
||||||
|
|
||||||
assert localPropertiesFile.exists()
|
repositories {
|
||||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
plugins {
|
||||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
id "com.android.application" version "8.1.0" apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
include ":app"
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
PODS:
|
|
||||||
- Flutter (1.0.0)
|
|
||||||
- flutter_inappwebview (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- flutter_inappwebview/Core (= 0.0.1)
|
|
||||||
- OrderedSet (~> 5.0)
|
|
||||||
- flutter_inappwebview/Core (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- OrderedSet (~> 5.0)
|
|
||||||
- OrderedSet (5.0.0)
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- Flutter (from `Flutter`)
|
|
||||||
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
|
|
||||||
|
|
||||||
SPEC REPOS:
|
|
||||||
trunk:
|
|
||||||
- OrderedSet
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
|
||||||
Flutter:
|
|
||||||
:path: Flutter
|
|
||||||
flutter_inappwebview:
|
|
||||||
:path: ".symlinks/plugins/flutter_inappwebview/ios"
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
|
||||||
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
|
|
||||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
|
||||||
|
|
||||||
COCOAPODS: 1.12.0
|
|
12
ios/RunnerTests/RunnerTests.swift
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,17 +1,117 @@
|
|||||||
class ActivityAction {
|
import 'package:sendtrain/classes/media.dart';
|
||||||
ActivityAction(
|
|
||||||
{required this.id,
|
|
||||||
required this.title,
|
|
||||||
required this.description,
|
|
||||||
this.repetitions,
|
|
||||||
this.time,
|
|
||||||
this.weight});
|
|
||||||
|
|
||||||
final int id;
|
class ActivityAction {
|
||||||
final String title;
|
int id;
|
||||||
final String description;
|
String title;
|
||||||
final int? repetitions;
|
String description;
|
||||||
final int? weight;
|
Set activityActionSet;
|
||||||
// in milliseconds
|
List<Media>? media;
|
||||||
final int? time;
|
|
||||||
|
ActivityAction({
|
||||||
|
required this.id,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
required this.activityActionSet,
|
||||||
|
this.media,
|
||||||
|
});
|
||||||
|
|
||||||
|
List<List<Map<String, dynamic>>> items() {
|
||||||
|
List<List<Map<String, dynamic>>> sets = [];
|
||||||
|
Reps reps = activityActionSet.reps;
|
||||||
|
int totalActions = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < activityActionSet.total; i++) {
|
||||||
|
List<Map<String, dynamic>> actions = [];
|
||||||
|
int? weight = _setWeight(i);
|
||||||
|
|
||||||
|
actions.add({
|
||||||
|
'actionID': totalActions++,
|
||||||
|
'name': title,
|
||||||
|
'type': reps.type,
|
||||||
|
'amount': reps.amounts[i],
|
||||||
|
'weight': weight,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (activityActionSet.type == 'alternating') {
|
||||||
|
if (reps.rest != null) {
|
||||||
|
actions.add({
|
||||||
|
'actionID': totalActions++,
|
||||||
|
'name': 'Rest',
|
||||||
|
'type': 'seconds',
|
||||||
|
'amount': reps.rest! ~/ 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.add({
|
||||||
|
'actionID': totalActions++,
|
||||||
|
'name': title,
|
||||||
|
'type': reps.type,
|
||||||
|
'amount': reps.amounts[i],
|
||||||
|
'weights': weight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.add({
|
||||||
|
'actionID': totalActions++,
|
||||||
|
'name': 'Rest',
|
||||||
|
'type': 'seconds',
|
||||||
|
'amount': activityActionSet.rest ~/ 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
sets.add(actions);
|
||||||
|
|
||||||
|
// sets.add([{
|
||||||
|
// 'actionID': totalActions++,
|
||||||
|
// 'name': 'Rest',
|
||||||
|
// 'type': 'seconds',
|
||||||
|
// 'amount': activityActionSet.rest ~/ 1000,
|
||||||
|
// }]);
|
||||||
|
|
||||||
|
// for (int j = 0; i < activityActionSet.reps.amounts; j++) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
int? _setWeight(setNum) {
|
||||||
|
Reps reps = activityActionSet.reps;
|
||||||
|
|
||||||
|
if (reps.weights.length == activityActionSet.total) {
|
||||||
|
return reps.weights[setNum];
|
||||||
|
} else if (reps.weights.length == 1) {
|
||||||
|
return reps.weights[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Set {
|
||||||
|
String type;
|
||||||
|
int total;
|
||||||
|
int rest;
|
||||||
|
Reps reps;
|
||||||
|
|
||||||
|
Set({
|
||||||
|
required this.type,
|
||||||
|
required this.total,
|
||||||
|
required this.rest,
|
||||||
|
required this.reps,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Reps {
|
||||||
|
String type;
|
||||||
|
List<int> tempo;
|
||||||
|
List<int> amounts;
|
||||||
|
List<int> weights = [];
|
||||||
|
int? rest;
|
||||||
|
|
||||||
|
Reps({
|
||||||
|
required this.type,
|
||||||
|
required this.tempo,
|
||||||
|
required this.amounts,
|
||||||
|
required this.weights,
|
||||||
|
this.rest,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class Media {
|
class Media {
|
||||||
Media(
|
Media(
|
||||||
|
121
lib/database.dart
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:drift_flutter/drift_flutter.dart';
|
||||||
|
|
||||||
|
part 'database.g.dart';
|
||||||
|
|
||||||
|
|
||||||
|
enum SessionStatus {
|
||||||
|
pending,
|
||||||
|
started,
|
||||||
|
completed,
|
||||||
|
missed
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sessions extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
TextColumn get title => text().withLength(min: 3, max: 32)();
|
||||||
|
TextColumn get content => text().named('body')();
|
||||||
|
TextColumn get status => textEnum<SessionStatus>()();
|
||||||
|
DateTimeColumn get date => dateTime().nullable()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SessionActivities extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
IntColumn get sessionId => integer().references(Sessions, #id)();
|
||||||
|
IntColumn get activityId => integer().references(Activities, #id)();
|
||||||
|
TextColumn get results => text().nullable()();
|
||||||
|
TextColumn get achievements => text().nullable()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ActivityCategories {
|
||||||
|
fundamentals,
|
||||||
|
conditioning,
|
||||||
|
advanced,
|
||||||
|
custom,
|
||||||
|
pro
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ActivityType {
|
||||||
|
strength,
|
||||||
|
power,
|
||||||
|
conditioning,
|
||||||
|
hypertrophy,
|
||||||
|
endurance,
|
||||||
|
stability,
|
||||||
|
mobility,
|
||||||
|
flexibility,
|
||||||
|
rehabilitation,
|
||||||
|
technical
|
||||||
|
}
|
||||||
|
|
||||||
|
class Activities extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
TextColumn get title => text().withLength(min: 3, max: 32)();
|
||||||
|
TextColumn get type => textEnum<ActivityType>()();
|
||||||
|
TextColumn get description => text().named('body')();
|
||||||
|
TextColumn get category => textEnum<ActivityCategories>()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActivityActions extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
IntColumn get activityId => integer().references(Activities, #id)();
|
||||||
|
IntColumn get actionId => integer().references(Actions, #id)();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Actions extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
TextColumn get title => text().withLength(min: 3, max: 32)();
|
||||||
|
TextColumn get description => text().named('body')();
|
||||||
|
TextColumn get set => text()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObjectMediaItems extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
IntColumn get objectId => integer().references(Actions, #id)();
|
||||||
|
IntColumn get mediaId => integer().references(MediaItems, #id)();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MediaType {
|
||||||
|
youtube,
|
||||||
|
image
|
||||||
|
}
|
||||||
|
class MediaItems extends Table {
|
||||||
|
IntColumn get id => integer().autoIncrement()();
|
||||||
|
TextColumn get title => text().withLength(min: 3, max: 32)();
|
||||||
|
TextColumn get description => text().named('body')();
|
||||||
|
TextColumn get reference => text().withLength(min: 3, max: 32)();
|
||||||
|
TextColumn get type => textEnum<MediaType>()();
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DriftDatabase(tables: [
|
||||||
|
Sessions,
|
||||||
|
SessionActivities,
|
||||||
|
Activities,
|
||||||
|
ActivityActions,
|
||||||
|
Actions,
|
||||||
|
ObjectMediaItems,
|
||||||
|
MediaItems
|
||||||
|
])
|
||||||
|
|
||||||
|
class AppDatabase extends _$AppDatabase {
|
||||||
|
// After generating code, this class needs to define a `schemaVersion` getter
|
||||||
|
// and a constructor telling drift where the database should be stored.
|
||||||
|
// These are described in the getting started guide: https://drift.simonbinder.eu/setup/
|
||||||
|
AppDatabase() : super(_openConnection());
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get schemaVersion => 1;
|
||||||
|
|
||||||
|
static QueryExecutor _openConnection() {
|
||||||
|
// `driftDatabase` from `package:drift_flutter` stores the database in
|
||||||
|
// `getApplicationDocumentsDirectory()`.
|
||||||
|
return driftDatabase(name: 'sendtrain');
|
||||||
|
}
|
||||||
|
}
|
4487
lib/database.g.dart
Normal file
@ -1,4 +1,8 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sendtrain/database.dart';
|
||||||
|
import 'package:sendtrain/models/activity_timer_model.dart';
|
||||||
import 'package:sendtrain/screens/activities_screen.dart';
|
import 'package:sendtrain/screens/activities_screen.dart';
|
||||||
import 'package:sendtrain/screens/sessions_screen.dart';
|
import 'package:sendtrain/screens/sessions_screen.dart';
|
||||||
|
|
||||||
@ -42,7 +46,7 @@ class _AppState extends State<App> {
|
|||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
|
padding: const EdgeInsets.fromLTRB(0, 50, 0, 0),
|
||||||
child: <Widget>[
|
child: <Widget>[
|
||||||
const SessionsScreen(),
|
SessionsScreen(),
|
||||||
const ActivitiesScreen(),
|
const ActivitiesScreen(),
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@ -88,5 +92,86 @@ class _AppState extends State<App> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const SendTrain());
|
// final database = AppDatabase();
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Projecting @ Climbers Rock',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.started,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Moonboard @ Boardroom',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.pending,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Moonboard @ Boardroom',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.completed,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Projecting @ Climbers Rock',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.completed,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Off-Wall Training',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.missed,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.sessions).insert(SessionsCompanion.insert(
|
||||||
|
// title: 'Off-Wall Training',
|
||||||
|
// content: 'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
|
// status: SessionStatus.completed,
|
||||||
|
// date: Value(DateTime.now())));
|
||||||
|
|
||||||
|
// database.into(database.activities).insert(ActivitiesCompanion.insert(
|
||||||
|
// title: "test activity",
|
||||||
|
// type: ActivityType.technical,
|
||||||
|
// description: "test training activity",
|
||||||
|
// category: ActivityCategories.fundamentals));
|
||||||
|
|
||||||
|
// database
|
||||||
|
// .into(database.sessionActivities)
|
||||||
|
// .insert(SessionActivitiesCompanion.insert(
|
||||||
|
// sessionId: 1,
|
||||||
|
// activityId: 1,
|
||||||
|
// results: Value("results json, will need to test"),
|
||||||
|
// achievements: Value("comma, seperated, items"),
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// database.into(database.actions).insert(ActionsCompanion.insert(
|
||||||
|
// title: "test action title",
|
||||||
|
// description: "teste action description",
|
||||||
|
// set: "not sure how the json will work yet",
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// database
|
||||||
|
// .into(database.activityActions)
|
||||||
|
// .insert(ActivityActionsCompanion.insert(
|
||||||
|
// activityId: 1,
|
||||||
|
// actionId: 1,
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// database.into(database.mediaItems).insert(MediaItemsCompanion.insert(
|
||||||
|
// title: "test youtube media item",
|
||||||
|
// description: "this is a test youtube item",
|
||||||
|
// reference: "sZVAEy9UmoY",
|
||||||
|
// type: MediaType.youtube));
|
||||||
|
|
||||||
|
// database
|
||||||
|
// .into(database.objectMediaItems)
|
||||||
|
// .insert(ObjectMediaItemsCompanion.insert(objectId: 1, mediaId: 1));
|
||||||
|
|
||||||
|
runApp(
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (context) => ActivityTimerModel(),
|
||||||
|
child: const SendTrain(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
161
lib/models/activity_timer_model.dart
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
|
|
||||||
|
class ActivityTimerModel with ChangeNotifier {
|
||||||
|
int _actionCounter = 0;
|
||||||
|
ActivityModel? _activity;
|
||||||
|
List _sets = [];
|
||||||
|
int _currentActionNum = 0;
|
||||||
|
int _currentSetNum = 0;
|
||||||
|
Timer? _periodicTimer;
|
||||||
|
double _progress = 0;
|
||||||
|
ItemScrollController? _isc;
|
||||||
|
int _totalTime = 0;
|
||||||
|
|
||||||
|
int get actionCount => _actionCounter;
|
||||||
|
int get currentActionNum => _currentActionNum;
|
||||||
|
dynamic get currentAction => currentSet[_currentActionNum];
|
||||||
|
int get currentSetNum => _currentSetNum;
|
||||||
|
dynamic get currentSet => _sets[_currentSetNum];
|
||||||
|
ActivityModel? get activity => _activity;
|
||||||
|
List get sets => _sets;
|
||||||
|
Timer? get periodicTimer => _periodicTimer;
|
||||||
|
bool get isActive => _isActive();
|
||||||
|
double get progress => _progress;
|
||||||
|
int get totalTime => _totalTime;
|
||||||
|
|
||||||
|
void setup(ActivityModel activity) {
|
||||||
|
if (_activity == null || activity.id != _activity?.id) {
|
||||||
|
_periodicTimer?.cancel();
|
||||||
|
_progress = 0;
|
||||||
|
_isc = null;
|
||||||
|
_activity = activity;
|
||||||
|
_sets = activity.actions[0].items();
|
||||||
|
_currentActionNum = 0;
|
||||||
|
_currentSetNum = 0;
|
||||||
|
setActionCount();
|
||||||
|
getTotalTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToIndex(_currentSetNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getTotalTime() {
|
||||||
|
int time = 0;
|
||||||
|
for(int setIndex = 0; _sets.length > setIndex; setIndex++) {
|
||||||
|
for (int actionIndex = 0; _sets[setIndex].length > actionIndex; actionIndex++) {
|
||||||
|
var action = _sets[setIndex][actionIndex];
|
||||||
|
if (action['type'] == 'seconds') {
|
||||||
|
time = time + action['amount'] as int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
_progress = 0;
|
||||||
|
_currentActionNum = 0;
|
||||||
|
_currentSetNum = 0;
|
||||||
|
_periodicTimer!.cancel();
|
||||||
|
setActionCount();
|
||||||
|
moveToIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setScrollController(ItemScrollController isc) {
|
||||||
|
_isc = isc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCurrentItem(int setNum, int actionNum) {
|
||||||
|
if (setNum == _currentSetNum && actionNum == _currentActionNum) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalActions() {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < _sets.length; i++) {
|
||||||
|
count = count + _sets[i].length as int;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setActionCount() {
|
||||||
|
_actionCounter = currentAction['amount'];
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause() {
|
||||||
|
_periodicTimer!.cancel();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
_periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
|
||||||
|
switch (currentAction['type']) {
|
||||||
|
// we don't want to count down
|
||||||
|
// if its repititions
|
||||||
|
case 'repititions':
|
||||||
|
break;
|
||||||
|
case 'seconds':
|
||||||
|
if (_actionCounter > 0) {
|
||||||
|
_actionCounter--;
|
||||||
|
_totalTime--;
|
||||||
|
} else {
|
||||||
|
nextAction(_currentActionNum + 1);
|
||||||
|
setActionCount();
|
||||||
|
}
|
||||||
|
updateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateProgress() {
|
||||||
|
_progress = (currentAction['actionID'] +
|
||||||
|
(1.0 - _actionCounter / currentAction['amount'])) /
|
||||||
|
totalActions();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAction(int setNum, int actionNum, String type) {
|
||||||
|
_currentActionNum = actionNum;
|
||||||
|
_currentSetNum = setNum;
|
||||||
|
notifyListeners();
|
||||||
|
moveToIndex(_currentSetNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nextAction(int nextActionIndex) {
|
||||||
|
if (currentSet.length > nextActionIndex) {
|
||||||
|
setAction(_currentSetNum, nextActionIndex, 'automatic');
|
||||||
|
} else if (_sets.length > _currentSetNum + 1) {
|
||||||
|
// if the item isn't in the set
|
||||||
|
// increment the set and reset action index
|
||||||
|
setAction(_currentSetNum + 1, 0, 'automatic');
|
||||||
|
} else {
|
||||||
|
// if we're done all the sets
|
||||||
|
// cancel timer and reset activity
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveToIndex(int index) {
|
||||||
|
if (_isc != null && _isc!.isAttached) {
|
||||||
|
_isc?.scrollTo(
|
||||||
|
index: index,
|
||||||
|
duration: Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOutCubic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isActive() {
|
||||||
|
return (_periodicTimer != null && _periodicTimer!.isActive) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:sendtrain/classes/activity_action.dart';
|
||||||
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
|
|
||||||
import '../widgets/activities_header.dart';
|
import '../widgets/activities_header.dart';
|
||||||
import '../widgets/activity_card.dart';
|
import '../widgets/activity_card.dart';
|
||||||
@ -11,9 +13,34 @@ class ActivitiesScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ActivitiesScreenState extends State<ActivitiesScreen> {
|
class _ActivitiesScreenState extends State<ActivitiesScreen> {
|
||||||
|
|
||||||
|
final data = ActivityModel(
|
||||||
|
id: 1,
|
||||||
|
categories: ['power'],
|
||||||
|
description: 'description',
|
||||||
|
title: 'activity',
|
||||||
|
type: 'fundamentals',
|
||||||
|
actions: List.generate(
|
||||||
|
10,
|
||||||
|
(i) => ActivityAction(
|
||||||
|
id: 1,
|
||||||
|
title: 'test action',
|
||||||
|
description: 'test description',
|
||||||
|
activityActionSet: Set(
|
||||||
|
type: 'drop_set',
|
||||||
|
total: 3,
|
||||||
|
rest: 300000,
|
||||||
|
reps: Reps(
|
||||||
|
type: 'count',
|
||||||
|
tempo: [2, 3, 5],
|
||||||
|
amounts: [5, 3, 2],
|
||||||
|
weights: [50, 70, 80],
|
||||||
|
rest: 20000))),
|
||||||
|
));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<Widget> activities = List.generate(10, (i) => ActivityCard());
|
List<Widget> activities = List.generate(10, (i) => ActivityCard(activity: data));
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 15, 10, 0),
|
padding: const EdgeInsets.fromLTRB(10, 15, 10, 0),
|
||||||
|
@ -1,52 +1,113 @@
|
|||||||
|
import 'package:drift/drift.dart' hide Column;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:sendtrain/database.dart';
|
||||||
import '../widgets/session_card.dart';
|
import '../widgets/session_card.dart';
|
||||||
|
|
||||||
class SessionsScreen extends StatelessWidget {
|
class SessionsScreen extends StatelessWidget {
|
||||||
const SessionsScreen({super.key});
|
final AppDatabase database = AppDatabase();
|
||||||
|
SessionsScreen({super.key});
|
||||||
|
|
||||||
|
Future<List<Session>> getSessions() async {
|
||||||
|
// database.managers.sessions.filter((session) => session.status(SessionStatus.pending));
|
||||||
|
return await database.managers.sessions.get();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<Widget> previousSessions =
|
return FutureBuilder<List<Session>>(
|
||||||
List.generate(10, (i) => const SessionCard(state: 1, type: 1));
|
future: getSessions(),
|
||||||
Widget upcomingSession = const SessionCard(state: 2);
|
builder: (context, snapshot) {
|
||||||
Widget currentSession = const SessionCard();
|
if (snapshot.hasData) {
|
||||||
|
final sessions = snapshot.data!;
|
||||||
|
final pending = sessions.where((session) => session.status == SessionStatus.completed || session.status == SessionStatus.missed);
|
||||||
|
final upcoming = sessions.firstWhere((session) => session.status == SessionStatus.pending);
|
||||||
|
final current = sessions.firstWhere((session) => session.status == SessionStatus.started);
|
||||||
|
|
||||||
return Column(
|
List<Widget> previousSessions = List.generate(pending.length, (i) => SessionCard(type: 1, session: pending.elementAt(i)));
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Widget upcomingSession =
|
||||||
children: <Widget>[
|
SessionCard(session: upcoming);
|
||||||
const Padding(
|
Widget currentSession = SessionCard(session: current);
|
||||||
padding: EdgeInsets.fromLTRB(15, 5, 0, 0),
|
|
||||||
child: Text(
|
database.close();
|
||||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
|
||||||
'Current:')),
|
return Column(
|
||||||
currentSession,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const Padding(
|
children: <Widget>[
|
||||||
padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
const Padding(
|
||||||
child: Text(
|
padding: EdgeInsets.fromLTRB(15, 5, 0, 0),
|
||||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
child: Text(
|
||||||
'Upcoming:')),
|
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
upcomingSession,
|
'Current:')),
|
||||||
const Padding(
|
currentSession,
|
||||||
padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
const Padding(
|
||||||
child: Text(
|
padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
||||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
child: Text(
|
||||||
'Previous:')),
|
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
SizedBox(
|
'Upcoming:')),
|
||||||
width: double.infinity,
|
upcomingSession,
|
||||||
height: 160,
|
const Padding(
|
||||||
child: GridView.count(
|
padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
||||||
padding: const EdgeInsets.fromLTRB(15, 10, 0, 0),
|
child: Text(
|
||||||
scrollDirection: Axis.horizontal,
|
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
crossAxisSpacing: 5,
|
'Previous:')),
|
||||||
mainAxisSpacing: 5,
|
SizedBox(
|
||||||
crossAxisCount: 1,
|
width: double.infinity,
|
||||||
children: previousSessions))
|
height: 160,
|
||||||
// Flexible(
|
child: GridView.count(
|
||||||
// child: ListView(
|
padding: const EdgeInsets.fromLTRB(15, 10, 0, 0),
|
||||||
// scrollDirection: Axis.vertical,
|
scrollDirection: Axis.horizontal,
|
||||||
// children: previousSessions,
|
crossAxisSpacing: 5,
|
||||||
// )),
|
mainAxisSpacing: 5,
|
||||||
],
|
crossAxisCount: 1,
|
||||||
);
|
children: previousSessions))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// List<Widget> previousSessions = List.generate(
|
||||||
|
// 10, (i) => SessionCard(state: 1, type: 1, session: _sessions.first));
|
||||||
|
// Widget upcomingSession = SessionCard(state: 2, session: _sessions.first);
|
||||||
|
// Widget currentSession = SessionCard(session: _sessions.first);
|
||||||
|
|
||||||
|
// return Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: <Widget>[
|
||||||
|
// const Padding(
|
||||||
|
// padding: EdgeInsets.fromLTRB(15, 5, 0, 0),
|
||||||
|
// child: Text(
|
||||||
|
// style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
|
// 'Current:')),
|
||||||
|
// currentSession,
|
||||||
|
// const Padding(
|
||||||
|
// padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
||||||
|
// child: Text(
|
||||||
|
// style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
|
// 'Upcoming:')),
|
||||||
|
// upcomingSession,
|
||||||
|
// const Padding(
|
||||||
|
// padding: EdgeInsets.fromLTRB(15, 30, 0, 0),
|
||||||
|
// child: Text(
|
||||||
|
// style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
|
// 'Previous:')),
|
||||||
|
// SizedBox(
|
||||||
|
// width: double.infinity,
|
||||||
|
// height: 160,
|
||||||
|
// child: GridView.count(
|
||||||
|
// padding: const EdgeInsets.fromLTRB(15, 10, 0, 0),
|
||||||
|
// scrollDirection: Axis.horizontal,
|
||||||
|
// crossAxisSpacing: 5,
|
||||||
|
// mainAxisSpacing: 5,
|
||||||
|
// crossAxisCount: 1,
|
||||||
|
// children: previousSessions))
|
||||||
|
// // Flexible(
|
||||||
|
// // child: ListView(
|
||||||
|
// // scrollDirection: Axis.vertical,
|
||||||
|
// // children: previousSessions,
|
||||||
|
// // )),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ class ActivitiesHeader extends StatefulWidget {
|
|||||||
const ActivitiesHeader({super.key});
|
const ActivitiesHeader({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ActivitiesHeaderState createState() => _ActivitiesHeaderState();
|
State<ActivitiesHeader> createState() => ActivitiesHeaderState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ActivitiesHeaderState extends State<ActivitiesHeader> {
|
class ActivitiesHeaderState extends State<ActivitiesHeader> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -21,12 +21,12 @@ class _ActivitiesHeaderState extends State<ActivitiesHeader> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return const Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 10),
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: const <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
108
lib/widgets/activity_action_view.dart
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
import 'package:sendtrain/classes/activity_action.dart';
|
||||||
|
import 'package:sendtrain/models/activity_timer_model.dart';
|
||||||
|
|
||||||
|
class ActivityActionView extends StatefulWidget {
|
||||||
|
const ActivityActionView({super.key, required this.action});
|
||||||
|
final ActivityAction action;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityActionView> createState() => ActivityActionViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActivityActionViewState extends State<ActivityActionView> {
|
||||||
|
final ItemScrollController itemScrollController = ItemScrollController();
|
||||||
|
final ScrollOffsetController scrollOffsetController =
|
||||||
|
ScrollOffsetController();
|
||||||
|
final ItemPositionsListener itemPositionsListener =
|
||||||
|
ItemPositionsListener.create();
|
||||||
|
final ScrollOffsetListener scrollOffsetListener =
|
||||||
|
ScrollOffsetListener.create();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ActivityTimerModel atm =
|
||||||
|
Provider.of<ActivityTimerModel>(context, listen: true);
|
||||||
|
List<List<Map<String, dynamic>>> sets = atm.activity!.actions[0].items();
|
||||||
|
|
||||||
|
// we need to set the scroll controller
|
||||||
|
// so we can update the selected item position
|
||||||
|
atm.setScrollController(itemScrollController);
|
||||||
|
|
||||||
|
return Expanded(
|
||||||
|
child: ScrollablePositionedList.builder(
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 20),
|
||||||
|
itemCount: widget.action.activityActionSet.total,
|
||||||
|
itemScrollController: itemScrollController,
|
||||||
|
scrollOffsetController: scrollOffsetController,
|
||||||
|
itemPositionsListener: itemPositionsListener,
|
||||||
|
scrollOffsetListener: scrollOffsetListener,
|
||||||
|
itemBuilder: (BuildContext context, int setNum) {
|
||||||
|
List<GestureDetector> content = [];
|
||||||
|
List<Map<String, dynamic>> set = sets[setNum];
|
||||||
|
|
||||||
|
for (int actionNum = 0; actionNum < set.length; actionNum++) {
|
||||||
|
Map<String, dynamic> setItem = set[actionNum];
|
||||||
|
|
||||||
|
content.add(GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
atm.setAction(setNum, actionNum, 'manual');
|
||||||
|
atm.setActionCount();
|
||||||
|
|
||||||
|
itemScrollController.scrollTo(
|
||||||
|
index: setNum,
|
||||||
|
duration: Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOutCubic);
|
||||||
|
},
|
||||||
|
child: Row(children: [
|
||||||
|
Ink(
|
||||||
|
width: 70,
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
color: atm.isCurrentItem(setNum, actionNum)
|
||||||
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
|
: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
'${setNum + 1}.${actionNum + 1} ')),
|
||||||
|
Expanded(
|
||||||
|
child: Ink(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
color: atm.isCurrentItem(setNum, actionNum)
|
||||||
|
? Theme.of(context).colorScheme.surfaceBright
|
||||||
|
: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
'${setItem['name']}: ${setItem['amount']} ${setItem['type']}')))
|
||||||
|
])));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setNum == 0) {
|
||||||
|
return Card(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(0),
|
||||||
|
topRight: Radius.circular(0),
|
||||||
|
bottomLeft: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10)),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Column(children: content));
|
||||||
|
} else {
|
||||||
|
return Card(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10),
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomLeft: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10)),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Column(children: content));
|
||||||
|
}
|
||||||
|
// return Column(children: contents);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +1,127 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:sendtrain/classes/activity_action.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sendtrain/classes/media.dart';
|
||||||
import 'package:sendtrain/models/activity_model.dart';
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
|
import 'package:sendtrain/models/activity_timer_model.dart';
|
||||||
|
import 'package:sendtrain/widgets/activity_view.dart';
|
||||||
|
|
||||||
class ActivityCard extends StatelessWidget {
|
class ActivityCard extends StatefulWidget {
|
||||||
ActivityCard({super.key});
|
final ActivityModel activity;
|
||||||
|
|
||||||
final data = ActivityModel(
|
const ActivityCard({super.key, required this.activity});
|
||||||
id: 1,
|
|
||||||
categories: ['power'],
|
@override
|
||||||
description: 'description',
|
State<ActivityCard> createState() => ActivityCardState();
|
||||||
title: 'activity',
|
}
|
||||||
type: 'fundamentals',
|
|
||||||
actions: List.generate(
|
class ActivityCardState extends State<ActivityCard> {
|
||||||
10,
|
String formattedTime(int timeInSecond) {
|
||||||
(i) => ActivityAction(
|
int sec = timeInSecond % 60;
|
||||||
id: 1,
|
int min = (timeInSecond / 60).floor();
|
||||||
title: 'exercise',
|
String minute = min.toString().length <= 1 ? "0$min" : "$min";
|
||||||
description: 'description',
|
String second = sec.toString().length <= 1 ? "0$sec" : "$sec";
|
||||||
repetitions: 5,
|
return "$minute:$second";
|
||||||
time: 5200)));
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final ActivityTimerModel atm =
|
||||||
|
Provider.of<ActivityTimerModel>(context, listen: false);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
clipBehavior: Clip.hardEdge,
|
color: atm.activity?.id == widget.activity.id
|
||||||
child: Align(
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
alignment: Alignment.center,
|
: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
child: Text(
|
clipBehavior: Clip.hardEdge,
|
||||||
data.title,
|
child: InkWell(
|
||||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
onTap: () => showGeneralDialog(
|
||||||
),
|
barrierColor: Colors.black.withOpacity(0.5),
|
||||||
));
|
transitionDuration: const Duration(milliseconds: 220),
|
||||||
|
transitionBuilder: (BuildContext context,
|
||||||
|
Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation,
|
||||||
|
Widget child) {
|
||||||
|
Animation<Offset> custom = Tween<Offset>(
|
||||||
|
begin: const Offset(0.0, 1.0),
|
||||||
|
end: const Offset(0.0, 0.0))
|
||||||
|
.animate(animation);
|
||||||
|
return SlideTransition(
|
||||||
|
position: custom,
|
||||||
|
child: Dialog.fullscreen(
|
||||||
|
child: ActivityView(activity: widget.activity)));
|
||||||
|
},
|
||||||
|
barrierDismissible: true,
|
||||||
|
barrierLabel: '',
|
||||||
|
context: context,
|
||||||
|
pageBuilder: (context, animation1, animation2) {
|
||||||
|
return Container();
|
||||||
|
}),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
ListTile(
|
||||||
|
leading: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 60,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: findMediaByType(
|
||||||
|
widget.activity.actions[0].media, 'image')),
|
||||||
|
// color: Colors.blue,
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.all(Radius.elliptical(10, 10)),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
title: Consumer<ActivityTimerModel>(
|
||||||
|
builder: (context, atm, child) {
|
||||||
|
if (atm.activity?.id == widget.activity.id) {
|
||||||
|
return Text(
|
||||||
|
maxLines: 1,
|
||||||
|
"${widget.activity.title} (${formattedTime(atm.totalTime)})");
|
||||||
|
} else {
|
||||||
|
return Text(maxLines: 1, widget.activity.title);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
subtitle: Text(maxLines: 2, widget.activity.description),
|
||||||
|
trailing: IconButton(
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: Icon(Icons.close_rounded),
|
||||||
|
onPressed: () {
|
||||||
|
showAdaptiveDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertDialog(
|
||||||
|
title: const Text('Activity Removal'),
|
||||||
|
content: const Text('Would you like to permanently remove this activity from the current session?'),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'Cancel'),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'OK'),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProvider findMediaByType(List<Media>? media, String type) {
|
||||||
|
var found = media?.where((m) => m.type == 'image');
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
return NetworkImage(found.first.reference);
|
||||||
|
} else {
|
||||||
|
// Element is not found
|
||||||
|
return const AssetImage('assets/images/placeholder.jpg');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
214
lib/widgets/activity_view.dart
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sendtrain/classes/activity_action.dart';
|
||||||
|
import 'package:sendtrain/classes/media.dart';
|
||||||
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
|
import 'package:sendtrain/models/activity_timer_model.dart';
|
||||||
|
import 'package:sendtrain/widgets/activity_action_view.dart';
|
||||||
|
import 'package:sendtrain/widgets/media_card.dart';
|
||||||
|
|
||||||
|
class ActivityView extends StatefulWidget {
|
||||||
|
const ActivityView({super.key, required this.activity});
|
||||||
|
final ActivityModel activity;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityView> createState() => _ActivityViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityViewState extends State<ActivityView> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ActivityModel activity = widget.activity;
|
||||||
|
ActivityTimerModel atm =
|
||||||
|
Provider.of<ActivityTimerModel>(context, listen: false);
|
||||||
|
|
||||||
|
atm.setup(activity);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
floatingActionButtonLocation: ExpandableFab.location,
|
||||||
|
floatingActionButton: ExpandableFab(
|
||||||
|
distance: 70,
|
||||||
|
type: ExpandableFabType.up,
|
||||||
|
overlayStyle: ExpandableFabOverlayStyle(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
blur: 10,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
FloatingActionButton.extended(
|
||||||
|
icon: const Icon(Icons.history_outlined),
|
||||||
|
label: Text('Restart'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
FloatingActionButton.extended(
|
||||||
|
icon: const Icon(Icons.done_all_outlined),
|
||||||
|
label: Text('Done'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
FloatingActionButton.extended(
|
||||||
|
icon: const Icon(Icons.edit_outlined),
|
||||||
|
label: Text('Edit'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
body: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
AppBar(
|
||||||
|
centerTitle: true,
|
||||||
|
title: const Text('Activity', style: TextStyle(fontSize: 15)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 15, right: 20, top: 15, bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
|
activity.title)),
|
||||||
|
ActivityViewCategories(categories: activity.categories),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 0, bottom: 20, left: 15, right: 15),
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: const TextStyle(fontSize: 15),
|
||||||
|
activity.description)),
|
||||||
|
ActivityViewMedia(activity: activity),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 30, 0, 10),
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
'Actions')),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||||
|
child: Card(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(10),
|
||||||
|
topRight: Radius.circular(10)),
|
||||||
|
),
|
||||||
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
child: Row(children: [
|
||||||
|
Ink(
|
||||||
|
width: 70,
|
||||||
|
color: Theme.of(context).colorScheme.primaryContainer,
|
||||||
|
child: Consumer<ActivityTimerModel>(
|
||||||
|
builder: (context, atm, child) {
|
||||||
|
return IconButton(
|
||||||
|
alignment: AlignmentDirectional.center,
|
||||||
|
icon: atm.isActive
|
||||||
|
? const Icon(Icons.pause_rounded)
|
||||||
|
: const Icon(Icons.play_arrow_rounded),
|
||||||
|
onPressed: () =>
|
||||||
|
{atm.isActive ? atm.pause() : atm.start()});
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Stack(alignment: Alignment.center, children: [
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Consumer<ActivityTimerModel>(
|
||||||
|
builder: (context, atm, child) {
|
||||||
|
return Text(
|
||||||
|
style: const TextStyle(fontSize: 20),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
'${atm.actionCount} ${atm.currentAction['type']}');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
padding: EdgeInsets.only(right: 15),
|
||||||
|
child: Consumer<ActivityTimerModel>(
|
||||||
|
builder: (context, atm, child) {
|
||||||
|
return Text(
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
'${atm.currentAction['actionID'] + 1} of ${atm.totalActions()}');
|
||||||
|
})),
|
||||||
|
])),
|
||||||
|
]))),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 14, right: 14),
|
||||||
|
child:
|
||||||
|
Consumer<ActivityTimerModel>(builder: (context, atm, child) {
|
||||||
|
return LinearProgressIndicator(
|
||||||
|
value: atm.progress,
|
||||||
|
semanticsLabel: 'Activity Progress',
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
ActivityActionView(action: activity.actions[0]),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActivityViewCategories extends StatelessWidget {
|
||||||
|
const ActivityViewCategories({super.key, this.categories});
|
||||||
|
|
||||||
|
final List<String>? categories;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 10),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
itemCount: categories?.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 5),
|
||||||
|
child: ActionChip(
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
avatar: const Icon(Icons.check_circle_outline),
|
||||||
|
label: Text(maxLines: 1, '${categories?[index]}'),
|
||||||
|
onPressed: () {},
|
||||||
|
));
|
||||||
|
},
|
||||||
|
))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActivityViewMedia extends StatelessWidget {
|
||||||
|
const ActivityViewMedia({super.key, this.activity});
|
||||||
|
|
||||||
|
final ActivityModel? activity;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Media> media = [];
|
||||||
|
|
||||||
|
for (ActivityAction action in activity!.actions) {
|
||||||
|
if (action.media!.isNotEmpty) {
|
||||||
|
media.addAll(action.media as Iterable<Media>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> mediaCards =
|
||||||
|
List.generate(media.length, (i) => MediaCard(media: media[i]));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 100,
|
||||||
|
child: GridView.count(
|
||||||
|
padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
crossAxisSpacing: 5,
|
||||||
|
mainAxisSpacing: 5,
|
||||||
|
crossAxisCount: 1,
|
||||||
|
children: mediaCards))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ class MediaCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
YoutubePlayerController _controller = YoutubePlayerController(
|
YoutubePlayerController controller = YoutubePlayerController(
|
||||||
initialVideoId: media.reference,
|
initialVideoId: media.reference,
|
||||||
flags: const YoutubePlayerFlags(
|
flags: const YoutubePlayerFlags(
|
||||||
autoPlay: false, mute: true, showLiveFullscreenButton: false));
|
autoPlay: false, mute: true, showLiveFullscreenButton: false));
|
||||||
@ -31,7 +31,7 @@ class MediaCard extends StatelessWidget {
|
|||||||
return Image(image: NetworkImage(media.reference));
|
return Image(image: NetworkImage(media.reference));
|
||||||
} else if (media.type == "youtube") {
|
} else if (media.type == "youtube") {
|
||||||
return YoutubePlayer(
|
return YoutubePlayer(
|
||||||
controller: _controller,
|
controller: controller,
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,24 @@ import 'package:intl/intl.dart';
|
|||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:sendtrain/classes/activity_action.dart';
|
import 'package:sendtrain/classes/activity_action.dart';
|
||||||
import 'package:sendtrain/classes/media.dart';
|
import 'package:sendtrain/classes/media.dart';
|
||||||
|
import 'package:sendtrain/database.dart' hide ActivityAction;
|
||||||
import 'package:sendtrain/models/activity_model.dart';
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
import 'package:sendtrain/models/session_model.dart';
|
import 'package:sendtrain/models/session_model.dart';
|
||||||
import 'package:sendtrain/widgets/session_view.dart';
|
import 'package:sendtrain/widgets/session_view.dart';
|
||||||
|
|
||||||
class SessionCard extends StatelessWidget {
|
class SessionCard extends StatelessWidget {
|
||||||
final int state;
|
|
||||||
final int type;
|
final int type;
|
||||||
const SessionCard({super.key, this.state = 0, this.type = 0});
|
final Session session;
|
||||||
|
const SessionCard({super.key, this.type = 0, required this.session});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
initializeDateFormatting('en');
|
initializeDateFormatting('en');
|
||||||
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
|
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
|
||||||
|
|
||||||
Color color = (state == 0)
|
Color color = (session.status == SessionStatus.started)
|
||||||
? const Color(0xff3A5FB6)
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
: ThemeData.dark(useMaterial3: true).colorScheme.background;
|
: Theme.of(context).colorScheme.surfaceContainerLow;
|
||||||
|
|
||||||
// place holder until we can retrieve real data
|
// place holder until we can retrieve real data
|
||||||
final data = SessionModel(
|
final data = SessionModel(
|
||||||
@ -35,86 +36,113 @@ class SessionCard extends StatelessWidget {
|
|||||||
type: 'fundamental',
|
type: 'fundamental',
|
||||||
categories: ['strength', 'power'],
|
categories: ['strength', 'power'],
|
||||||
description:
|
description:
|
||||||
"Campus board session, focussing on explosiveness and contact strength.",
|
"Campus board session, focusing on explosiveness and contact strength.",
|
||||||
actions: [
|
actions: [
|
||||||
ActivityAction(
|
ActivityAction(
|
||||||
id: 1,
|
id: 1,
|
||||||
title: '1, 3, 5 - left hand start',
|
title: '1, 3, 5',
|
||||||
description:
|
description:
|
||||||
'move from rungs 1, 3, and 5, alternating arms on each movement',
|
'Move between the first, third, and fifth rungs, alternating hands. Rest and alternate sides, to start',
|
||||||
repetitions: 1),
|
media: [
|
||||||
ActivityAction(
|
Media(
|
||||||
id: 2,
|
id: 1,
|
||||||
title: 'Rest',
|
reference:
|
||||||
description: 'rest for alotted time',
|
'https://www.climbing.com/wp-content/uploads/2022/06/campus-board-e1655470701154.jpeg',
|
||||||
time: 15000),
|
type: 'image',
|
||||||
ActivityAction(
|
description: 'Campus board movement'),
|
||||||
id: 3,
|
Media(
|
||||||
title: '1, 3, 5 - right hand start',
|
id: 1,
|
||||||
description:
|
reference: '7ACyeOP-Hxo',
|
||||||
'move from rungs 1, 3, and 5, alternating arms on each movement',
|
type: 'youtube',
|
||||||
repetitions: 1),
|
description: 'How to campus board')
|
||||||
ActivityAction(
|
],
|
||||||
id: 4,
|
activityActionSet: Set(
|
||||||
title: 'Rest',
|
type: 'drop_set',
|
||||||
description: 'rest for alotted time',
|
total: 3,
|
||||||
time: 300000),
|
rest: 300000,
|
||||||
ActivityAction(
|
reps: Reps(
|
||||||
id: 5,
|
type: 'repititions',
|
||||||
title: 'Repeat',
|
tempo: [0],
|
||||||
description: 'repeat cycle',
|
amounts: [1, 1, 1],
|
||||||
repetitions: 5)
|
weights: [0],
|
||||||
|
rest: 20000))),
|
||||||
],
|
],
|
||||||
resources: ['https://www.youtube.com/watch?v=bLz0xp1PEm4']),
|
resources: ['https://www.youtube.com/watch?v=bLz0xp1PEm4']),
|
||||||
ActivityModel(
|
ActivityModel(
|
||||||
id: 1,
|
id: 2,
|
||||||
title: 'Projecting',
|
title: 'Projecting',
|
||||||
type: 'fundamental',
|
type: 'fundamental',
|
||||||
categories: ['technique', 'conditioning'],
|
categories: ['technique', 'conditioning'],
|
||||||
description:
|
description:
|
||||||
"Session focussed on attempting a climb at or beyond your perceived limit.",
|
"Session focused on attempting a climb at or beyond your perceived limit.",
|
||||||
actions: [
|
actions: [
|
||||||
ActivityAction(
|
ActivityAction(
|
||||||
id: 1,
|
id: 1,
|
||||||
title: 'attempt boulder',
|
title: 'Attempt Climb',
|
||||||
description: 'attempt boulder project',
|
description:
|
||||||
repetitions: 1),
|
'Attempt your selected climb, if you fall off early in the climb, attempt again. 1 repitition equals roughly doing all the moves, not necessarily in 1 attempt.',
|
||||||
ActivityAction(
|
media: [
|
||||||
id: 2,
|
Media(
|
||||||
title: 'Rest',
|
id: 1,
|
||||||
description: 'rest for alotted time',
|
reference:
|
||||||
time: 300000),
|
'https://www.climbing.com/wp-content/uploads/2022/07/Fixed-44.jpg',
|
||||||
ActivityAction(
|
type: 'image',
|
||||||
id: 5,
|
description: 'Projecting a climb'),
|
||||||
title: 'Repeat',
|
Media(
|
||||||
description: 'repeat cycle',
|
id: 1,
|
||||||
repetitions: 5)
|
reference: 'BgheYcxhrsw',
|
||||||
|
type: 'youtube',
|
||||||
|
description: 'How to project climbs')
|
||||||
|
],
|
||||||
|
activityActionSet: Set(
|
||||||
|
type: 'standard',
|
||||||
|
total: 10,
|
||||||
|
rest: 300000,
|
||||||
|
reps: Reps(
|
||||||
|
type: 'repititions',
|
||||||
|
tempo: [0],
|
||||||
|
amounts: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
weights: [0],
|
||||||
|
rest: 0))),
|
||||||
],
|
],
|
||||||
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
|
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
|
||||||
ActivityModel(
|
ActivityModel(
|
||||||
id: 1,
|
id: 3,
|
||||||
title: 'Weighted Pull Ups',
|
title: 'Long Block Pulls',
|
||||||
type: 'fundamental',
|
type: 'Hypertrophy',
|
||||||
categories: ['Strength', 'Power'],
|
categories: ['Strength', 'Power'],
|
||||||
description:
|
description:
|
||||||
"Weight pullups to increase strength and maximal pulling force.",
|
"Block pull on a edge of a specific size and time to induce a hypertrophic effect on the formarms.",
|
||||||
actions: [
|
actions: [
|
||||||
ActivityAction(
|
ActivityAction(
|
||||||
id: 1,
|
id: 1,
|
||||||
title: 'pull ups',
|
title: 'Long Pulls',
|
||||||
description: 'pull ups',
|
description:
|
||||||
repetitions: 5,
|
'Select your desired weight to pull, add it to the block. You should aim for an effort level of 8-9 when reaching the end of the set time, going to failure will result in significantly extended recovery time.',
|
||||||
weight: 100),
|
media: [
|
||||||
ActivityAction(
|
Media(
|
||||||
id: 2,
|
id: 1,
|
||||||
title: 'Rest',
|
reference:
|
||||||
description: 'rest for alotted time',
|
'https://trailandcrag.com/sites/default/files/inline-images/05-min_3.jpg',
|
||||||
time: 300000),
|
type: 'image',
|
||||||
ActivityAction(
|
description: 'Block pull example'),
|
||||||
id: 5,
|
Media(
|
||||||
title: 'Repeat',
|
id: 1,
|
||||||
description: 'repeat cycle',
|
reference: 'sZVAEy9UmoY',
|
||||||
repetitions: 5)
|
type: 'youtube',
|
||||||
|
description:
|
||||||
|
'Principals of Grip gains, and related protocols')
|
||||||
|
],
|
||||||
|
activityActionSet: Set(
|
||||||
|
type: 'alternating',
|
||||||
|
total: 5,
|
||||||
|
rest: 5000,
|
||||||
|
reps: Reps(
|
||||||
|
type: 'seconds',
|
||||||
|
tempo: [0],
|
||||||
|
amounts: [5, 5, 5, 5, 5],
|
||||||
|
weights: [80, 80, 80, 80, 80],
|
||||||
|
rest: 5000))),
|
||||||
],
|
],
|
||||||
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
|
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
|
||||||
],
|
],
|
||||||
@ -149,7 +177,7 @@ class SessionCard extends StatelessWidget {
|
|||||||
margin: const EdgeInsets.fromLTRB(15, 15, 15, 0),
|
margin: const EdgeInsets.fromLTRB(15, 15, 15, 0),
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
// splashColor: Colors.deepPurple,
|
splashColor: Colors.deepPurple,
|
||||||
onTap: () => showGeneralDialog(
|
onTap: () => showGeneralDialog(
|
||||||
barrierColor: Colors.black.withOpacity(0.5),
|
barrierColor: Colors.black.withOpacity(0.5),
|
||||||
transitionDuration: const Duration(milliseconds: 220),
|
transitionDuration: const Duration(milliseconds: 220),
|
||||||
@ -163,7 +191,7 @@ class SessionCard extends StatelessWidget {
|
|||||||
.animate(animation);
|
.animate(animation);
|
||||||
return SlideTransition(
|
return SlideTransition(
|
||||||
position: custom,
|
position: custom,
|
||||||
child: Dialog.fullscreen(child: SessionView(data: data)));
|
child: Dialog.fullscreen(child: SessionView(data: data, session: session)));
|
||||||
},
|
},
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: '',
|
barrierLabel: '',
|
||||||
@ -189,8 +217,32 @@ class SessionCard extends StatelessWidget {
|
|||||||
BorderRadius.all(Radius.elliptical(10, 10)),
|
BorderRadius.all(Radius.elliptical(10, 10)),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
title: Text(maxLines: 1, data.title),
|
title: Text(maxLines: 1, session.title),
|
||||||
subtitle: Text(maxLines: 1, dateFormat.format(data.date)),
|
subtitle: Text(maxLines: 1, dateFormat.format(session.date as DateTime)),
|
||||||
|
trailing: IconButton(
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: Icon(Icons.close_rounded),
|
||||||
|
onPressed: () {
|
||||||
|
showAdaptiveDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertDialog(
|
||||||
|
title: const Text('Session Removal'),
|
||||||
|
content: const Text(
|
||||||
|
'Would you like to permanently remove this session?'),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'Cancel'),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'OK'),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15),
|
contentPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15),
|
||||||
@ -198,17 +250,17 @@ class SessionCard extends StatelessWidget {
|
|||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(fontWeight: FontWeight.w300),
|
style: const TextStyle(fontWeight: FontWeight.w300),
|
||||||
data.content),
|
session.content),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Card(
|
return Card(
|
||||||
color: const Color.fromARGB(125, 0, 0, 0),
|
color: color,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
// overlayColor: MaterialStateColor(Colors.deepPurple as int),
|
// overlayColor: MaterialStateColor(Colors.deepPurple as int),
|
||||||
// splashColor: Colors.deepPurple,
|
splashColor: Colors.deepPurple,
|
||||||
borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)),
|
borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)),
|
||||||
onTap: () => showGeneralDialog(
|
onTap: () => showGeneralDialog(
|
||||||
// barrierColor: Colors.black.withOpacity(0.5),
|
// barrierColor: Colors.black.withOpacity(0.5),
|
||||||
@ -224,7 +276,7 @@ class SessionCard extends StatelessWidget {
|
|||||||
return SlideTransition(
|
return SlideTransition(
|
||||||
position: custom,
|
position: custom,
|
||||||
child:
|
child:
|
||||||
Dialog.fullscreen(child: SessionView(data: data)));
|
Dialog.fullscreen(child: SessionView(data: data, session: session)));
|
||||||
},
|
},
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: '',
|
barrierLabel: '',
|
||||||
@ -251,11 +303,11 @@ class SessionCard extends StatelessWidget {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
data.title,
|
session.title,
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
dateFormat.format(data.date),
|
dateFormat.format(session.date as DateTime),
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
),
|
),
|
||||||
])))));
|
])))));
|
||||||
|
@ -1,57 +1,87 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
|
|
||||||
import 'package:sendtrain/classes/media.dart';
|
import 'package:sendtrain/classes/media.dart';
|
||||||
|
import 'package:sendtrain/database.dart';
|
||||||
import 'package:sendtrain/models/activity_model.dart';
|
import 'package:sendtrain/models/activity_model.dart';
|
||||||
import 'package:sendtrain/models/session_model.dart';
|
import 'package:sendtrain/models/session_model.dart';
|
||||||
|
import 'package:sendtrain/widgets/activity_card.dart';
|
||||||
import 'package:sendtrain/widgets/media_card.dart';
|
import 'package:sendtrain/widgets/media_card.dart';
|
||||||
|
|
||||||
class SessionView extends StatelessWidget {
|
class SessionView extends StatelessWidget {
|
||||||
const SessionView({super.key, required this.data});
|
const SessionView({super.key, required this.data, required this.session});
|
||||||
|
|
||||||
final SessionModel data;
|
final SessionModel data;
|
||||||
|
final Session session;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
initializeDateFormatting('en');
|
initializeDateFormatting('en');
|
||||||
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
|
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
|
||||||
|
|
||||||
return Column(
|
return Scaffold(
|
||||||
mainAxisSize: MainAxisSize.min,
|
floatingActionButtonLocation: ExpandableFab.location,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
floatingActionButton: ExpandableFab(
|
||||||
children: <Widget>[
|
distance: 70,
|
||||||
AppBar(
|
type: ExpandableFabType.up,
|
||||||
centerTitle: true,
|
overlayStyle: ExpandableFabOverlayStyle(
|
||||||
title: Text('Session @ ${dateFormat.format(data.date)}',
|
color: Colors.black.withOpacity(0.5),
|
||||||
style: const TextStyle(fontSize: 15)),
|
blur: 10,
|
||||||
),
|
),
|
||||||
Padding(
|
children: [
|
||||||
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10),
|
FloatingActionButton.extended(
|
||||||
child: Text(
|
icon: const Icon(Icons.history_outlined),
|
||||||
maxLines: 1,
|
label: Text('Restart'),
|
||||||
style:
|
onPressed: () {},
|
||||||
const TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
|
),
|
||||||
data.title)),
|
FloatingActionButton.extended(
|
||||||
SessionViewAchievements(achievements: data.achievements),
|
icon: const Icon(Icons.done_all_outlined),
|
||||||
Padding(
|
label: Text('Done'),
|
||||||
padding: const EdgeInsets.only(left: 15, right: 15),
|
onPressed: () {},
|
||||||
child: Text(textAlign: TextAlign.center, data.content)),
|
),
|
||||||
SessionViewMedia(media: data.media),
|
FloatingActionButton.extended(
|
||||||
const Padding(
|
icon: const Icon(Icons.edit_outlined),
|
||||||
padding: EdgeInsets.only(top: 25, bottom: 10),
|
label: Text('Edit'),
|
||||||
child: Text(
|
onPressed: () {},
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
),
|
||||||
'Activities:')),
|
]),
|
||||||
SessionViewActivities(activities: data.activities),
|
body: Column(
|
||||||
// TextButton(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
// onPressed: () {
|
children: <Widget>[
|
||||||
// Navigator.pop(context);
|
AppBar(
|
||||||
// },
|
centerTitle: true,
|
||||||
// child: const Text('Close'),
|
title: Text('Session @ ${dateFormat.format(session.date as DateTime)}',
|
||||||
// ),
|
style: const TextStyle(fontSize: 15)),
|
||||||
],
|
),
|
||||||
);
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 15, right: 20, top: 15, bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 25, fontWeight: FontWeight.bold),
|
||||||
|
session.title)),
|
||||||
|
SessionViewAchievements(achievements: data.achievements),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
|
child:
|
||||||
|
Text(style: const TextStyle(fontSize: 15), session.content)),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 30, 0, 10),
|
||||||
|
child: Text(
|
||||||
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
'Media:')),
|
||||||
|
SessionViewMedia(media: data.media),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 30, 0, 10),
|
||||||
|
child: Text(
|
||||||
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
'Activites:')),
|
||||||
|
SessionViewActivities(activities: data.activities),
|
||||||
|
],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,57 +94,11 @@ class SessionViewActivities extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
shrinkWrap: true,
|
// shrinkWrap: true,
|
||||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
itemCount: activities?.length,
|
itemCount: activities?.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return Card(
|
return ActivityCard(activity: activities![index]);
|
||||||
color: const Color(0xff3A5FB6),
|
|
||||||
child: ListTile(
|
|
||||||
// dense: true,
|
|
||||||
focusColor: const Color(0xff3A5FB6),
|
|
||||||
shape: const RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.elliptical(10, 10))),
|
|
||||||
onTap: () => showGeneralDialog(
|
|
||||||
barrierColor: Colors.black.withOpacity(0.5),
|
|
||||||
transitionDuration: const Duration(milliseconds: 220),
|
|
||||||
transitionBuilder: (BuildContext context,
|
|
||||||
Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation,
|
|
||||||
Widget child) {
|
|
||||||
Animation<Offset> custom = Tween<Offset>(
|
|
||||||
begin: const Offset(0.0, 1.0),
|
|
||||||
end: const Offset(0.0, 0.0))
|
|
||||||
.animate(animation);
|
|
||||||
return SlideTransition(
|
|
||||||
position: custom,
|
|
||||||
child: Dialog(
|
|
||||||
child: Flex(
|
|
||||||
direction: Axis.vertical,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text('${activities?[index].title}'),
|
|
||||||
Text('${activities?[index].categories}'),
|
|
||||||
Text('${activities?[index].description}'),
|
|
||||||
Text('${activities?[index].resources}'),
|
|
||||||
Text('${activities?[index].actions[0].title}'),
|
|
||||||
Text(
|
|
||||||
'${activities?[index].actions[0].description}'),
|
|
||||||
])));
|
|
||||||
},
|
|
||||||
barrierDismissible: true,
|
|
||||||
barrierLabel: '',
|
|
||||||
context: context,
|
|
||||||
pageBuilder: (context, animation1, animation2) {
|
|
||||||
return Container();
|
|
||||||
}),
|
|
||||||
enableFeedback: true,
|
|
||||||
title: Text(maxLines: 1, '${activities?[index].title}'),
|
|
||||||
subtitle: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 3),
|
|
||||||
child:
|
|
||||||
Text(maxLines: 2, '${activities?[index].description}')),
|
|
||||||
));
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -144,22 +128,8 @@ class SessionViewAchievements extends StatelessWidget {
|
|||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
avatar: const Icon(Icons.check_circle_outline),
|
avatar: const Icon(Icons.check_circle_outline),
|
||||||
label: Text(maxLines: 1, '${achievements?[index]}'),
|
label: Text(maxLines: 1, '${achievements?[index]}'),
|
||||||
onPressed: () {
|
onPressed: () {},
|
||||||
// setState(() {
|
|
||||||
// favorite = !favorite;
|
|
||||||
// });
|
|
||||||
},
|
|
||||||
));
|
));
|
||||||
// return Card(
|
|
||||||
// child: ListTile(
|
|
||||||
// // dense: true,
|
|
||||||
// focusColor: Colors.deepPurple,
|
|
||||||
// shape: const RoundedRectangleBorder(
|
|
||||||
// borderRadius: BorderRadius.all(Radius.circular(10))),
|
|
||||||
// onTap: () {},
|
|
||||||
// enableFeedback: true,
|
|
||||||
// title: Text(maxLines: 1, '${achievements?[index]}'),
|
|
||||||
// ));
|
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
],
|
],
|
||||||
@ -179,16 +149,11 @@ class SessionViewMedia extends StatelessWidget {
|
|||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(top: 25),
|
|
||||||
child: Text(
|
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
|
||||||
'Media:')),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 100,
|
height: 100,
|
||||||
child: GridView.count(
|
child: GridView.count(
|
||||||
padding: const EdgeInsets.fromLTRB(15, 10, 0, 0),
|
padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
crossAxisSpacing: 5,
|
crossAxisSpacing: 5,
|
||||||
mainAxisSpacing: 5,
|
mainAxisSpacing: 5,
|
||||||
@ -198,24 +163,3 @@ class SessionViewMedia extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SizedBox(
|
|
||||||
// height: 100,
|
|
||||||
// width: double.infinity,
|
|
||||||
// child: ListView.builder(
|
|
||||||
// // scrollDirection: Axis.horizontal,
|
|
||||||
// padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
|
|
||||||
// itemCount: media?.length,
|
|
||||||
// itemBuilder: (BuildContext context, int index) {
|
|
||||||
// return Card(
|
|
||||||
// child: ListTile(
|
|
||||||
// dense: true,
|
|
||||||
// focusColor: Colors.deepPurple,
|
|
||||||
// shape: const RoundedRectangleBorder(
|
|
||||||
// borderRadius: BorderRadius.all(Radius.circular(10))),
|
|
||||||
// onTap: () {},
|
|
||||||
// enableFeedback: true,
|
|
||||||
// title: const Text(maxLines: 1, 'test'),
|
|
||||||
// ));
|
|
||||||
// }))
|
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
|
||||||
|
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
|
||||||
#define GENERATED_PLUGIN_REGISTRANT_
|
|
||||||
|
|
||||||
#include <flutter_linux/flutter_linux.h>
|
|
||||||
|
|
||||||
// Registers Flutter plugins.
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry);
|
|
||||||
|
|
||||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
|
@ -1,23 +0,0 @@
|
|||||||
#
|
|
||||||
# Generated file, do not edit.
|
|
||||||
#
|
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
|
||||||
)
|
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
|
||||||
|
|
||||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
|
||||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
|
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
|
||||||
endforeach(plugin)
|
|
||||||
|
|
||||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
|
||||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
|
||||||
endforeach(ffi_plugin)
|
|
@ -1,10 +0,0 @@
|
|||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
import FlutterMacOS
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|
||||||
}
|
|
12
macos/RunnerTests/RunnerTests.swift
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Cocoa
|
||||||
|
import FlutterMacOS
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
221
pubspec.lock
@ -1,221 +0,0 @@
|
|||||||
# Generated by pub
|
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
||||||
packages:
|
|
||||||
async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: async
|
|
||||||
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.10.0"
|
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.1"
|
|
||||||
characters:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: characters
|
|
||||||
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
clock:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: clock
|
|
||||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: collection
|
|
||||||
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.17.0"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.5"
|
|
||||||
fake_async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fake_async
|
|
||||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.1"
|
|
||||||
flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_inappwebview:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_inappwebview
|
|
||||||
sha256: f73505c792cf083d5566e1a94002311be497d984b5607f25be36d685cf6361cf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.7.2+3"
|
|
||||||
flutter_lints:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: flutter_lints
|
|
||||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
intl:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: intl
|
|
||||||
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.18.0"
|
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.5"
|
|
||||||
lints:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: lints
|
|
||||||
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.13"
|
|
||||||
material_color_utilities:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: material_color_utilities
|
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.0"
|
|
||||||
meta:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: meta
|
|
||||||
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.0"
|
|
||||||
path:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path
|
|
||||||
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.8.2"
|
|
||||||
scaler:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: scaler
|
|
||||||
sha256: d761b02e08445fa6617338c40903fb6cd2c77660000bafafe928b0287bd5f04a
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2+1"
|
|
||||||
sky_engine:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.99"
|
|
||||||
source_span:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_span
|
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.9.1"
|
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.11.0"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.1"
|
|
||||||
string_scanner:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: string_scanner
|
|
||||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
term_glyph:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: term_glyph
|
|
||||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.4.16"
|
|
||||||
vector_math:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_math
|
|
||||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.4"
|
|
||||||
youtube_player_flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: youtube_player_flutter
|
|
||||||
sha256: "72d487e1a1b9155a2dc9d448c137380791101a0ff623723195275ac275ac6942"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "8.1.2"
|
|
||||||
sdks:
|
|
||||||
dart: ">=2.19.2 <3.0.0"
|
|
||||||
flutter: ">=3.0.0"
|
|
18
pubspec.yaml
@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
version: 0.2.1
|
version: 0.2.1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.19.2 <3.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
@ -36,8 +36,15 @@ dependencies:
|
|||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
scaler: ^1.1.2+1
|
scaler: ^1.1.2+1
|
||||||
intl: ^0.18.0
|
intl: ^0.20.1
|
||||||
youtube_player_flutter: ^8.1.2
|
youtube_player_flutter: ^9.1.1
|
||||||
|
json_annotation: ^4.9.0
|
||||||
|
provider: ^6.1.2
|
||||||
|
scrollable_positioned_list: ^0.3.8
|
||||||
|
drift: ^2.22.1
|
||||||
|
flutter_expandable_fab: ^2.3.0
|
||||||
|
drift_flutter: ^0.2.2
|
||||||
|
flutter_local_notifications: ^18.0.1
|
||||||
|
|
||||||
flutter_launcher_name:
|
flutter_launcher_name:
|
||||||
name: "SendTrain"
|
name: "SendTrain"
|
||||||
@ -51,7 +58,10 @@ dev_dependencies:
|
|||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^5.0.0
|
||||||
|
build_runner: ^2.4.13
|
||||||
|
json_serializable: ^6.9.0
|
||||||
|
drift_dev: ^2.22.1
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
1
sendtrain/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
40
sendtrain/build.gradle.kts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.sendtrain.sendtrain"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.sendtrain.sendtrain"
|
||||||
|
minSdk = 24
|
||||||
|
targetSdk = 34
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation("com.android.support:appcompat-v7:28.0.0")
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
androidTestImplementation("com.android.support.test:runner:1.0.2")
|
||||||
|
androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2")
|
||||||
|
}
|
21
sendtrain/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.sendtrain.sendtrain;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
assertEquals("com.sendtrain.sendtrain", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
12
sendtrain/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.Sendtrain" />
|
||||||
|
|
||||||
|
</manifest>
|
170
sendtrain/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
30
sendtrain/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
6
sendtrain/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
BIN
sendtrain/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
sendtrain/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
sendtrain/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 982 B |
BIN
sendtrain/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
sendtrain/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
sendtrain/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
sendtrain/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
sendtrain/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
sendtrain/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
sendtrain/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 7.6 KiB |
10
sendtrain/src/main/res/values-night/themes.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Theme.Sendtrain" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Primary brand color. -->
|
||||||
|
<item name="colorPrimary">@color/purple_200</item>
|
||||||
|
<item name="colorPrimaryDark">@color/purple_700</item>
|
||||||
|
<item name="colorAccent">@color/teal_200</item>
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
</resources>
|
10
sendtrain/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="purple_200">#FFBB86FC</color>
|
||||||
|
<color name="purple_500">#FF6200EE</color>
|
||||||
|
<color name="purple_700">#FF3700B3</color>
|
||||||
|
<color name="teal_200">#FF03DAC5</color>
|
||||||
|
<color name="teal_700">#FF018786</color>
|
||||||
|
<color name="black">#FF000000</color>
|
||||||
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
</resources>
|
3
sendtrain/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">SendTrain</string>
|
||||||
|
</resources>
|
10
sendtrain/src/main/res/values/themes.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="Theme.Sendtrain" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Primary brand color. -->
|
||||||
|
<item name="colorPrimary">@color/purple_500</item>
|
||||||
|
<item name="colorPrimaryDark">@color/purple_700</item>
|
||||||
|
<item name="colorAccent">@color/teal_200</item>
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.sendtrain.sendtrain;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
public class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
public void addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
|
||||||
|
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// Generated file. Do not edit.
|
|
||||||
//
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
|
||||||
#define GENERATED_PLUGIN_REGISTRANT_
|
|
||||||
|
|
||||||
#include <flutter/plugin_registry.h>
|
|
||||||
|
|
||||||
// Registers Flutter plugins.
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry);
|
|
||||||
|
|
||||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
|
@ -1,23 +0,0 @@
|
|||||||
#
|
|
||||||
# Generated file, do not edit.
|
|
||||||
#
|
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
|
||||||
)
|
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
|
||||||
|
|
||||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
|
||||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
|
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
|
||||||
endforeach(plugin)
|
|
||||||
|
|
||||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
|
||||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
|
|
||||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
|
||||||
endforeach(ffi_plugin)
|
|