action display, and full display, started action editor
This commit is contained in:
parent
0cf62ec4b4
commit
60bc571987
@ -32,4 +32,6 @@ class ActionsDao extends DatabaseAccessor<AppDatabase> with _$ActionsDaoMixin {
|
|||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future createOrUpdate(ActionsCompanion action) => into(actions).insertOnConflictUpdate(action);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase() : super(_openConnection());
|
AppDatabase() : super(_openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 22;
|
int get schemaVersion => 33;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
@ -165,6 +165,9 @@ class ActivityActions extends Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum RepType { time, count }
|
enum RepType { time, count }
|
||||||
|
|
||||||
|
enum ActionStatus { pending, started, paused, complete }
|
||||||
|
|
||||||
class Actions extends Table {
|
class Actions extends Table {
|
||||||
IntColumn get id => integer().autoIncrement()();
|
IntColumn get id => integer().autoIncrement()();
|
||||||
TextColumn get title => text().withLength(min: 3, max: 64)();
|
TextColumn get title => text().withLength(min: 3, max: 64)();
|
||||||
@ -181,6 +184,10 @@ class Actions extends Table {
|
|||||||
TextColumn get setWeights => text().nullable()();
|
TextColumn get setWeights => text().nullable()();
|
||||||
BoolColumn get isAlternating => boolean().withDefault(Variable(false))();
|
BoolColumn get isAlternating => boolean().withDefault(Variable(false))();
|
||||||
TextColumn get tempo => text().withLength(min: 6, max: 36).nullable()();
|
TextColumn get tempo => text().withLength(min: 6, max: 36).nullable()();
|
||||||
|
TextColumn get status =>
|
||||||
|
textEnum<ActionStatus>().withDefault(Variable('pending'))();
|
||||||
|
TextColumn get state => text().withDefault(Variable(
|
||||||
|
"{\"currentSet\": 0, \"currentRep\": 0, \"currentActionType\": 0, \"currentTime\": 0, \"currentAction\": 0}"))();
|
||||||
TextColumn get set => text()();
|
TextColumn get set => text()();
|
||||||
DateTimeColumn get createdAt =>
|
DateTimeColumn get createdAt =>
|
||||||
dateTime().withDefault(Variable(DateTime.now()))();
|
dateTime().withDefault(Variable(DateTime.now()))();
|
||||||
|
@ -1532,6 +1532,22 @@ class $ActionsTable extends Actions with TableInfo<$ActionsTable, Action> {
|
|||||||
GeneratedColumn.checkTextLength(minTextLength: 6, maxTextLength: 36),
|
GeneratedColumn.checkTextLength(minTextLength: 6, maxTextLength: 36),
|
||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: false);
|
requiredDuringInsert: false);
|
||||||
|
static const VerificationMeta _statusMeta = const VerificationMeta('status');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumnWithTypeConverter<ActionStatus, String> status =
|
||||||
|
GeneratedColumn<String>('status', aliasedName, false,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: Variable('pending'))
|
||||||
|
.withConverter<ActionStatus>($ActionsTable.$converterstatus);
|
||||||
|
static const VerificationMeta _stateMeta = const VerificationMeta('state');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> state = GeneratedColumn<String>(
|
||||||
|
'state', aliasedName, false,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: Variable(
|
||||||
|
"{\"currentSet\": 0, \"currentRep\": 0, \"currentActionType\": 0, \"currentTime\": 0, \"currentAction\": 0}"));
|
||||||
static const VerificationMeta _setMeta = const VerificationMeta('set');
|
static const VerificationMeta _setMeta = const VerificationMeta('set');
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumn<String> set = GeneratedColumn<String>(
|
late final GeneratedColumn<String> set = GeneratedColumn<String>(
|
||||||
@ -1562,6 +1578,8 @@ class $ActionsTable extends Actions with TableInfo<$ActionsTable, Action> {
|
|||||||
setWeights,
|
setWeights,
|
||||||
isAlternating,
|
isAlternating,
|
||||||
tempo,
|
tempo,
|
||||||
|
status,
|
||||||
|
state,
|
||||||
set,
|
set,
|
||||||
createdAt
|
createdAt
|
||||||
];
|
];
|
||||||
@ -1653,6 +1671,11 @@ class $ActionsTable extends Actions with TableInfo<$ActionsTable, Action> {
|
|||||||
context.handle(
|
context.handle(
|
||||||
_tempoMeta, tempo.isAcceptableOrUnknown(data['tempo']!, _tempoMeta));
|
_tempoMeta, tempo.isAcceptableOrUnknown(data['tempo']!, _tempoMeta));
|
||||||
}
|
}
|
||||||
|
context.handle(_statusMeta, const VerificationResult.success());
|
||||||
|
if (data.containsKey('state')) {
|
||||||
|
context.handle(
|
||||||
|
_stateMeta, state.isAcceptableOrUnknown(data['state']!, _stateMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('set')) {
|
if (data.containsKey('set')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_setMeta, set.isAcceptableOrUnknown(data['set']!, _setMeta));
|
_setMeta, set.isAcceptableOrUnknown(data['set']!, _setMeta));
|
||||||
@ -1703,6 +1726,11 @@ class $ActionsTable extends Actions with TableInfo<$ActionsTable, Action> {
|
|||||||
.read(DriftSqlType.bool, data['${effectivePrefix}is_alternating'])!,
|
.read(DriftSqlType.bool, data['${effectivePrefix}is_alternating'])!,
|
||||||
tempo: attachedDatabase.typeMapping
|
tempo: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.string, data['${effectivePrefix}tempo']),
|
.read(DriftSqlType.string, data['${effectivePrefix}tempo']),
|
||||||
|
status: $ActionsTable.$converterstatus.fromSql(attachedDatabase
|
||||||
|
.typeMapping
|
||||||
|
.read(DriftSqlType.string, data['${effectivePrefix}status'])!),
|
||||||
|
state: attachedDatabase.typeMapping
|
||||||
|
.read(DriftSqlType.string, data['${effectivePrefix}state'])!,
|
||||||
set: attachedDatabase.typeMapping
|
set: attachedDatabase.typeMapping
|
||||||
.read(DriftSqlType.string, data['${effectivePrefix}set'])!,
|
.read(DriftSqlType.string, data['${effectivePrefix}set'])!,
|
||||||
createdAt: attachedDatabase.typeMapping
|
createdAt: attachedDatabase.typeMapping
|
||||||
@ -1717,6 +1745,8 @@ class $ActionsTable extends Actions with TableInfo<$ActionsTable, Action> {
|
|||||||
|
|
||||||
static JsonTypeConverter2<RepType, String, String> $converterrepType =
|
static JsonTypeConverter2<RepType, String, String> $converterrepType =
|
||||||
const EnumNameConverter<RepType>(RepType.values);
|
const EnumNameConverter<RepType>(RepType.values);
|
||||||
|
static JsonTypeConverter2<ActionStatus, String, String> $converterstatus =
|
||||||
|
const EnumNameConverter<ActionStatus>(ActionStatus.values);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Action extends DataClass implements Insertable<Action> {
|
class Action extends DataClass implements Insertable<Action> {
|
||||||
@ -1735,6 +1765,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
final String? setWeights;
|
final String? setWeights;
|
||||||
final bool isAlternating;
|
final bool isAlternating;
|
||||||
final String? tempo;
|
final String? tempo;
|
||||||
|
final ActionStatus status;
|
||||||
|
final String state;
|
||||||
final String set;
|
final String set;
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
const Action(
|
const Action(
|
||||||
@ -1753,6 +1785,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
this.setWeights,
|
this.setWeights,
|
||||||
required this.isAlternating,
|
required this.isAlternating,
|
||||||
this.tempo,
|
this.tempo,
|
||||||
|
required this.status,
|
||||||
|
required this.state,
|
||||||
required this.set,
|
required this.set,
|
||||||
required this.createdAt});
|
required this.createdAt});
|
||||||
@override
|
@override
|
||||||
@ -1792,6 +1826,11 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
if (!nullToAbsent || tempo != null) {
|
if (!nullToAbsent || tempo != null) {
|
||||||
map['tempo'] = Variable<String>(tempo);
|
map['tempo'] = Variable<String>(tempo);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
map['status'] =
|
||||||
|
Variable<String>($ActionsTable.$converterstatus.toSql(status));
|
||||||
|
}
|
||||||
|
map['state'] = Variable<String>(state);
|
||||||
map['set'] = Variable<String>(set);
|
map['set'] = Variable<String>(set);
|
||||||
map['created_at'] = Variable<DateTime>(createdAt);
|
map['created_at'] = Variable<DateTime>(createdAt);
|
||||||
return map;
|
return map;
|
||||||
@ -1829,6 +1868,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
isAlternating: Value(isAlternating),
|
isAlternating: Value(isAlternating),
|
||||||
tempo:
|
tempo:
|
||||||
tempo == null && nullToAbsent ? const Value.absent() : Value(tempo),
|
tempo == null && nullToAbsent ? const Value.absent() : Value(tempo),
|
||||||
|
status: Value(status),
|
||||||
|
state: Value(state),
|
||||||
set: Value(set),
|
set: Value(set),
|
||||||
createdAt: Value(createdAt),
|
createdAt: Value(createdAt),
|
||||||
);
|
);
|
||||||
@ -1854,6 +1895,9 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
setWeights: serializer.fromJson<String?>(json['setWeights']),
|
setWeights: serializer.fromJson<String?>(json['setWeights']),
|
||||||
isAlternating: serializer.fromJson<bool>(json['isAlternating']),
|
isAlternating: serializer.fromJson<bool>(json['isAlternating']),
|
||||||
tempo: serializer.fromJson<String?>(json['tempo']),
|
tempo: serializer.fromJson<String?>(json['tempo']),
|
||||||
|
status: $ActionsTable.$converterstatus
|
||||||
|
.fromJson(serializer.fromJson<String>(json['status'])),
|
||||||
|
state: serializer.fromJson<String>(json['state']),
|
||||||
set: serializer.fromJson<String>(json['set']),
|
set: serializer.fromJson<String>(json['set']),
|
||||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||||
);
|
);
|
||||||
@ -1878,6 +1922,9 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
'setWeights': serializer.toJson<String?>(setWeights),
|
'setWeights': serializer.toJson<String?>(setWeights),
|
||||||
'isAlternating': serializer.toJson<bool>(isAlternating),
|
'isAlternating': serializer.toJson<bool>(isAlternating),
|
||||||
'tempo': serializer.toJson<String?>(tempo),
|
'tempo': serializer.toJson<String?>(tempo),
|
||||||
|
'status': serializer
|
||||||
|
.toJson<String>($ActionsTable.$converterstatus.toJson(status)),
|
||||||
|
'state': serializer.toJson<String>(state),
|
||||||
'set': serializer.toJson<String>(set),
|
'set': serializer.toJson<String>(set),
|
||||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||||
};
|
};
|
||||||
@ -1899,6 +1946,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
Value<String?> setWeights = const Value.absent(),
|
Value<String?> setWeights = const Value.absent(),
|
||||||
bool? isAlternating,
|
bool? isAlternating,
|
||||||
Value<String?> tempo = const Value.absent(),
|
Value<String?> tempo = const Value.absent(),
|
||||||
|
ActionStatus? status,
|
||||||
|
String? state,
|
||||||
String? set,
|
String? set,
|
||||||
DateTime? createdAt}) =>
|
DateTime? createdAt}) =>
|
||||||
Action(
|
Action(
|
||||||
@ -1923,6 +1972,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
setWeights: setWeights.present ? setWeights.value : this.setWeights,
|
setWeights: setWeights.present ? setWeights.value : this.setWeights,
|
||||||
isAlternating: isAlternating ?? this.isAlternating,
|
isAlternating: isAlternating ?? this.isAlternating,
|
||||||
tempo: tempo.present ? tempo.value : this.tempo,
|
tempo: tempo.present ? tempo.value : this.tempo,
|
||||||
|
status: status ?? this.status,
|
||||||
|
state: state ?? this.state,
|
||||||
set: set ?? this.set,
|
set: set ?? this.set,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
);
|
);
|
||||||
@ -1956,6 +2007,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
? data.isAlternating.value
|
? data.isAlternating.value
|
||||||
: this.isAlternating,
|
: this.isAlternating,
|
||||||
tempo: data.tempo.present ? data.tempo.value : this.tempo,
|
tempo: data.tempo.present ? data.tempo.value : this.tempo,
|
||||||
|
status: data.status.present ? data.status.value : this.status,
|
||||||
|
state: data.state.present ? data.state.value : this.state,
|
||||||
set: data.set.present ? data.set.value : this.set,
|
set: data.set.present ? data.set.value : this.set,
|
||||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||||
);
|
);
|
||||||
@ -1979,6 +2032,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
..write('setWeights: $setWeights, ')
|
..write('setWeights: $setWeights, ')
|
||||||
..write('isAlternating: $isAlternating, ')
|
..write('isAlternating: $isAlternating, ')
|
||||||
..write('tempo: $tempo, ')
|
..write('tempo: $tempo, ')
|
||||||
|
..write('status: $status, ')
|
||||||
|
..write('state: $state, ')
|
||||||
..write('set: $set, ')
|
..write('set: $set, ')
|
||||||
..write('createdAt: $createdAt')
|
..write('createdAt: $createdAt')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
@ -2002,6 +2057,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
setWeights,
|
setWeights,
|
||||||
isAlternating,
|
isAlternating,
|
||||||
tempo,
|
tempo,
|
||||||
|
status,
|
||||||
|
state,
|
||||||
set,
|
set,
|
||||||
createdAt);
|
createdAt);
|
||||||
@override
|
@override
|
||||||
@ -2023,6 +2080,8 @@ class Action extends DataClass implements Insertable<Action> {
|
|||||||
other.setWeights == this.setWeights &&
|
other.setWeights == this.setWeights &&
|
||||||
other.isAlternating == this.isAlternating &&
|
other.isAlternating == this.isAlternating &&
|
||||||
other.tempo == this.tempo &&
|
other.tempo == this.tempo &&
|
||||||
|
other.status == this.status &&
|
||||||
|
other.state == this.state &&
|
||||||
other.set == this.set &&
|
other.set == this.set &&
|
||||||
other.createdAt == this.createdAt);
|
other.createdAt == this.createdAt);
|
||||||
}
|
}
|
||||||
@ -2043,6 +2102,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
final Value<String?> setWeights;
|
final Value<String?> setWeights;
|
||||||
final Value<bool> isAlternating;
|
final Value<bool> isAlternating;
|
||||||
final Value<String?> tempo;
|
final Value<String?> tempo;
|
||||||
|
final Value<ActionStatus> status;
|
||||||
|
final Value<String> state;
|
||||||
final Value<String> set;
|
final Value<String> set;
|
||||||
final Value<DateTime> createdAt;
|
final Value<DateTime> createdAt;
|
||||||
const ActionsCompanion({
|
const ActionsCompanion({
|
||||||
@ -2061,6 +2122,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
this.setWeights = const Value.absent(),
|
this.setWeights = const Value.absent(),
|
||||||
this.isAlternating = const Value.absent(),
|
this.isAlternating = const Value.absent(),
|
||||||
this.tempo = const Value.absent(),
|
this.tempo = const Value.absent(),
|
||||||
|
this.status = const Value.absent(),
|
||||||
|
this.state = const Value.absent(),
|
||||||
this.set = const Value.absent(),
|
this.set = const Value.absent(),
|
||||||
this.createdAt = const Value.absent(),
|
this.createdAt = const Value.absent(),
|
||||||
});
|
});
|
||||||
@ -2080,6 +2143,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
this.setWeights = const Value.absent(),
|
this.setWeights = const Value.absent(),
|
||||||
this.isAlternating = const Value.absent(),
|
this.isAlternating = const Value.absent(),
|
||||||
this.tempo = const Value.absent(),
|
this.tempo = const Value.absent(),
|
||||||
|
this.status = const Value.absent(),
|
||||||
|
this.state = const Value.absent(),
|
||||||
required String set,
|
required String set,
|
||||||
this.createdAt = const Value.absent(),
|
this.createdAt = const Value.absent(),
|
||||||
}) : title = Value(title),
|
}) : title = Value(title),
|
||||||
@ -2104,6 +2169,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
Expression<String>? setWeights,
|
Expression<String>? setWeights,
|
||||||
Expression<bool>? isAlternating,
|
Expression<bool>? isAlternating,
|
||||||
Expression<String>? tempo,
|
Expression<String>? tempo,
|
||||||
|
Expression<String>? status,
|
||||||
|
Expression<String>? state,
|
||||||
Expression<String>? set,
|
Expression<String>? set,
|
||||||
Expression<DateTime>? createdAt,
|
Expression<DateTime>? createdAt,
|
||||||
}) {
|
}) {
|
||||||
@ -2123,6 +2190,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
if (setWeights != null) 'set_weights': setWeights,
|
if (setWeights != null) 'set_weights': setWeights,
|
||||||
if (isAlternating != null) 'is_alternating': isAlternating,
|
if (isAlternating != null) 'is_alternating': isAlternating,
|
||||||
if (tempo != null) 'tempo': tempo,
|
if (tempo != null) 'tempo': tempo,
|
||||||
|
if (status != null) 'status': status,
|
||||||
|
if (state != null) 'state': state,
|
||||||
if (set != null) 'set': set,
|
if (set != null) 'set': set,
|
||||||
if (createdAt != null) 'created_at': createdAt,
|
if (createdAt != null) 'created_at': createdAt,
|
||||||
});
|
});
|
||||||
@ -2144,6 +2213,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
Value<String?>? setWeights,
|
Value<String?>? setWeights,
|
||||||
Value<bool>? isAlternating,
|
Value<bool>? isAlternating,
|
||||||
Value<String?>? tempo,
|
Value<String?>? tempo,
|
||||||
|
Value<ActionStatus>? status,
|
||||||
|
Value<String>? state,
|
||||||
Value<String>? set,
|
Value<String>? set,
|
||||||
Value<DateTime>? createdAt}) {
|
Value<DateTime>? createdAt}) {
|
||||||
return ActionsCompanion(
|
return ActionsCompanion(
|
||||||
@ -2162,6 +2233,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
setWeights: setWeights ?? this.setWeights,
|
setWeights: setWeights ?? this.setWeights,
|
||||||
isAlternating: isAlternating ?? this.isAlternating,
|
isAlternating: isAlternating ?? this.isAlternating,
|
||||||
tempo: tempo ?? this.tempo,
|
tempo: tempo ?? this.tempo,
|
||||||
|
status: status ?? this.status,
|
||||||
|
state: state ?? this.state,
|
||||||
set: set ?? this.set,
|
set: set ?? this.set,
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
);
|
);
|
||||||
@ -2216,6 +2289,13 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
if (tempo.present) {
|
if (tempo.present) {
|
||||||
map['tempo'] = Variable<String>(tempo.value);
|
map['tempo'] = Variable<String>(tempo.value);
|
||||||
}
|
}
|
||||||
|
if (status.present) {
|
||||||
|
map['status'] =
|
||||||
|
Variable<String>($ActionsTable.$converterstatus.toSql(status.value));
|
||||||
|
}
|
||||||
|
if (state.present) {
|
||||||
|
map['state'] = Variable<String>(state.value);
|
||||||
|
}
|
||||||
if (set.present) {
|
if (set.present) {
|
||||||
map['set'] = Variable<String>(set.value);
|
map['set'] = Variable<String>(set.value);
|
||||||
}
|
}
|
||||||
@ -2243,6 +2323,8 @@ class ActionsCompanion extends UpdateCompanion<Action> {
|
|||||||
..write('setWeights: $setWeights, ')
|
..write('setWeights: $setWeights, ')
|
||||||
..write('isAlternating: $isAlternating, ')
|
..write('isAlternating: $isAlternating, ')
|
||||||
..write('tempo: $tempo, ')
|
..write('tempo: $tempo, ')
|
||||||
|
..write('status: $status, ')
|
||||||
|
..write('state: $state, ')
|
||||||
..write('set: $set, ')
|
..write('set: $set, ')
|
||||||
..write('createdAt: $createdAt')
|
..write('createdAt: $createdAt')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
@ -4412,6 +4494,8 @@ typedef $$ActionsTableCreateCompanionBuilder = ActionsCompanion Function({
|
|||||||
Value<String?> setWeights,
|
Value<String?> setWeights,
|
||||||
Value<bool> isAlternating,
|
Value<bool> isAlternating,
|
||||||
Value<String?> tempo,
|
Value<String?> tempo,
|
||||||
|
Value<ActionStatus> status,
|
||||||
|
Value<String> state,
|
||||||
required String set,
|
required String set,
|
||||||
Value<DateTime> createdAt,
|
Value<DateTime> createdAt,
|
||||||
});
|
});
|
||||||
@ -4431,6 +4515,8 @@ typedef $$ActionsTableUpdateCompanionBuilder = ActionsCompanion Function({
|
|||||||
Value<String?> setWeights,
|
Value<String?> setWeights,
|
||||||
Value<bool> isAlternating,
|
Value<bool> isAlternating,
|
||||||
Value<String?> tempo,
|
Value<String?> tempo,
|
||||||
|
Value<ActionStatus> status,
|
||||||
|
Value<String> state,
|
||||||
Value<String> set,
|
Value<String> set,
|
||||||
Value<DateTime> createdAt,
|
Value<DateTime> createdAt,
|
||||||
});
|
});
|
||||||
@ -4516,6 +4602,14 @@ class $$ActionsTableFilterComposer
|
|||||||
ColumnFilters<String> get tempo => $composableBuilder(
|
ColumnFilters<String> get tempo => $composableBuilder(
|
||||||
column: $table.tempo, builder: (column) => ColumnFilters(column));
|
column: $table.tempo, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
|
ColumnWithTypeConverterFilters<ActionStatus, ActionStatus, String>
|
||||||
|
get status => $composableBuilder(
|
||||||
|
column: $table.status,
|
||||||
|
builder: (column) => ColumnWithTypeConverterFilters(column));
|
||||||
|
|
||||||
|
ColumnFilters<String> get state => $composableBuilder(
|
||||||
|
column: $table.state, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
ColumnFilters<String> get set => $composableBuilder(
|
ColumnFilters<String> get set => $composableBuilder(
|
||||||
column: $table.set, builder: (column) => ColumnFilters(column));
|
column: $table.set, builder: (column) => ColumnFilters(column));
|
||||||
|
|
||||||
@ -4603,6 +4697,12 @@ class $$ActionsTableOrderingComposer
|
|||||||
ColumnOrderings<String> get tempo => $composableBuilder(
|
ColumnOrderings<String> get tempo => $composableBuilder(
|
||||||
column: $table.tempo, builder: (column) => ColumnOrderings(column));
|
column: $table.tempo, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
ColumnOrderings<String> get status => $composableBuilder(
|
||||||
|
column: $table.status, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
|
ColumnOrderings<String> get state => $composableBuilder(
|
||||||
|
column: $table.state, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
ColumnOrderings<String> get set => $composableBuilder(
|
ColumnOrderings<String> get set => $composableBuilder(
|
||||||
column: $table.set, builder: (column) => ColumnOrderings(column));
|
column: $table.set, builder: (column) => ColumnOrderings(column));
|
||||||
|
|
||||||
@ -4664,6 +4764,12 @@ class $$ActionsTableAnnotationComposer
|
|||||||
GeneratedColumn<String> get tempo =>
|
GeneratedColumn<String> get tempo =>
|
||||||
$composableBuilder(column: $table.tempo, builder: (column) => column);
|
$composableBuilder(column: $table.tempo, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumnWithTypeConverter<ActionStatus, String> get status =>
|
||||||
|
$composableBuilder(column: $table.status, builder: (column) => column);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get state =>
|
||||||
|
$composableBuilder(column: $table.state, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<String> get set =>
|
GeneratedColumn<String> get set =>
|
||||||
$composableBuilder(column: $table.set, builder: (column) => column);
|
$composableBuilder(column: $table.set, builder: (column) => column);
|
||||||
|
|
||||||
@ -4730,6 +4836,8 @@ class $$ActionsTableTableManager extends RootTableManager<
|
|||||||
Value<String?> setWeights = const Value.absent(),
|
Value<String?> setWeights = const Value.absent(),
|
||||||
Value<bool> isAlternating = const Value.absent(),
|
Value<bool> isAlternating = const Value.absent(),
|
||||||
Value<String?> tempo = const Value.absent(),
|
Value<String?> tempo = const Value.absent(),
|
||||||
|
Value<ActionStatus> status = const Value.absent(),
|
||||||
|
Value<String> state = const Value.absent(),
|
||||||
Value<String> set = const Value.absent(),
|
Value<String> set = const Value.absent(),
|
||||||
Value<DateTime> createdAt = const Value.absent(),
|
Value<DateTime> createdAt = const Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
@ -4749,6 +4857,8 @@ class $$ActionsTableTableManager extends RootTableManager<
|
|||||||
setWeights: setWeights,
|
setWeights: setWeights,
|
||||||
isAlternating: isAlternating,
|
isAlternating: isAlternating,
|
||||||
tempo: tempo,
|
tempo: tempo,
|
||||||
|
status: status,
|
||||||
|
state: state,
|
||||||
set: set,
|
set: set,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
),
|
),
|
||||||
@ -4768,6 +4878,8 @@ class $$ActionsTableTableManager extends RootTableManager<
|
|||||||
Value<String?> setWeights = const Value.absent(),
|
Value<String?> setWeights = const Value.absent(),
|
||||||
Value<bool> isAlternating = const Value.absent(),
|
Value<bool> isAlternating = const Value.absent(),
|
||||||
Value<String?> tempo = const Value.absent(),
|
Value<String?> tempo = const Value.absent(),
|
||||||
|
Value<ActionStatus> status = const Value.absent(),
|
||||||
|
Value<String> state = const Value.absent(),
|
||||||
required String set,
|
required String set,
|
||||||
Value<DateTime> createdAt = const Value.absent(),
|
Value<DateTime> createdAt = const Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
@ -4787,6 +4899,8 @@ class $$ActionsTableTableManager extends RootTableManager<
|
|||||||
setWeights: setWeights,
|
setWeights: setWeights,
|
||||||
isAlternating: isAlternating,
|
isAlternating: isAlternating,
|
||||||
tempo: tempo,
|
tempo: tempo,
|
||||||
|
status: status,
|
||||||
|
state: state,
|
||||||
set: set,
|
set: set,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
),
|
),
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -183,7 +183,7 @@ Future<void> seedDb(AppDatabase database) async {
|
|||||||
description:
|
description:
|
||||||
'$k Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
'$k Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
|
||||||
totalSets: 5,
|
totalSets: 5,
|
||||||
totalReps: "[5]",
|
totalReps: "[1]",
|
||||||
restBeforeSets: Value(30000),
|
restBeforeSets: Value(30000),
|
||||||
restBetweenSets: Value(300000),
|
restBetweenSets: Value(300000),
|
||||||
restBetweenReps: Value(15000),
|
restBetweenReps: Value(15000),
|
||||||
|
@ -9,3 +9,8 @@ String formattedTime(int timeInSecond) {
|
|||||||
String second = sec.toString().length <= 1 ? "0$sec" : "$sec";
|
String second = sec.toString().length <= 1 ? "0$sec" : "$sec";
|
||||||
return "$minute:$second";
|
return "$minute:$second";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int toSeconds(int milliseconds) {
|
||||||
|
int sec = (milliseconds / 1000).floor();
|
||||||
|
return sec;
|
||||||
|
}
|
||||||
|
@ -6,8 +6,12 @@ showMediaDetailWidget(BuildContext context, MediaItem media) {
|
|||||||
showEditorSheet(context, MediaDetails(media: media));
|
showEditorSheet(context, MediaDetails(media: media));
|
||||||
}
|
}
|
||||||
|
|
||||||
showGenericSheet(BuildContext context, Widget widget) {
|
showGenericSheet(BuildContext context, Widget widget,
|
||||||
|
[Color? backgroundColor]) {
|
||||||
|
backgroundColor ??= Theme.of(context).colorScheme.surfaceBright;
|
||||||
|
|
||||||
showModalBottomSheet<void>(
|
showModalBottomSheet<void>(
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0)),
|
topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0)),
|
||||||
@ -37,4 +41,4 @@ String jsonToDescription(List text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:sendtrain/database/database.dart';
|
import 'package:sendtrain/database/database.dart';
|
||||||
import 'package:sendtrain/helpers/widget_helpers.dart';
|
import 'package:sendtrain/helpers/widget_helpers.dart';
|
||||||
import 'package:sendtrain/models/activity_timer_model.dart';
|
import 'package:sendtrain/models/activity_timer_model.dart';
|
||||||
|
import 'package:sendtrain/providers/action_timer.dart';
|
||||||
import 'package:sendtrain/widgets/screens/activities_screen.dart';
|
import 'package:sendtrain/widgets/screens/activities_screen.dart';
|
||||||
import 'package:sendtrain/widgets/screens/sessions_screen.dart';
|
import 'package:sendtrain/widgets/screens/sessions_screen.dart';
|
||||||
// ignore: unused_import
|
// ignore: unused_import
|
||||||
@ -111,12 +112,14 @@ class _AppState extends State<App> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
var db = AppDatabase();
|
||||||
runApp(MultiProvider(
|
runApp(MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (context) => ActivityTimerModel()),
|
|
||||||
Provider<AppDatabase>(
|
Provider<AppDatabase>(
|
||||||
create: (context) => AppDatabase(),
|
create: (context) => db,
|
||||||
dispose: (context, db) => db.close()),
|
dispose: (context, db) => db.close()),
|
||||||
|
ChangeNotifierProvider(create: (context) => ActivityTimerModel()),
|
||||||
|
ChangeNotifierProvider(create: (context) => ActionTimer()),
|
||||||
],
|
],
|
||||||
child: const SendTrain(),
|
child: const SendTrain(),
|
||||||
));
|
));
|
||||||
|
259
lib/models/action_model.dart
Normal file
259
lib/models/action_model.dart
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:sendtrain/daos/actions_dao.dart';
|
||||||
|
import 'package:sendtrain/database/database.dart';
|
||||||
|
import 'package:sendtrain/helpers/date_time_helpers.dart';
|
||||||
|
|
||||||
|
class ActionModel {
|
||||||
|
final ActionsDao dao;
|
||||||
|
List<Item> items;
|
||||||
|
Action action;
|
||||||
|
|
||||||
|
ActionModel({required this.action, required AppDatabase db})
|
||||||
|
: dao = ActionsDao(db),
|
||||||
|
items = _generateItems(action);
|
||||||
|
|
||||||
|
int get id => action.id;
|
||||||
|
ActionStatus get status => action.status;
|
||||||
|
Map get state => json.decode(action.state);
|
||||||
|
List<Set> get sets => items.whereType<Set>().toList();
|
||||||
|
List<Item> get allItems => _flattenedItems();
|
||||||
|
int get totalTime {
|
||||||
|
int time = 0;
|
||||||
|
for (int i = 0; i < allItems.length; i++) {
|
||||||
|
Item item = allItems[i];
|
||||||
|
time += item.time ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toSeconds(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Item> _flattenedItems() {
|
||||||
|
List<Item> items = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < this.items.length; i++) {
|
||||||
|
Item item = this.items[i];
|
||||||
|
if (item.runtimeType == Set) {
|
||||||
|
Set setItem = item as Set;
|
||||||
|
for (int j = 0; j < setItem.items.length; j++) {
|
||||||
|
items.add(setItem.items[j]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Item> _generateItems(Action action) {
|
||||||
|
int totalItems = 0;
|
||||||
|
int setItems = 0;
|
||||||
|
List<Item> items = [];
|
||||||
|
final List setReps = json.decode(action.totalReps);
|
||||||
|
|
||||||
|
if (action.restBeforeSets != null) {
|
||||||
|
items.add(Rest(
|
||||||
|
id: totalItems,
|
||||||
|
position: totalItems,
|
||||||
|
action: action,
|
||||||
|
time: action.restBeforeSets!,
|
||||||
|
name: 'prepare'));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < action.totalSets; i++) {
|
||||||
|
final int totalReps;
|
||||||
|
|
||||||
|
if (setReps.length == 1) {
|
||||||
|
totalReps = setReps.first;
|
||||||
|
} else {
|
||||||
|
totalReps = setReps[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
totalItems += 1;
|
||||||
|
items.add(Set(
|
||||||
|
id: totalItems,
|
||||||
|
setOrder: setItems++,
|
||||||
|
position: totalItems,
|
||||||
|
action: action,
|
||||||
|
totalReps: totalReps));
|
||||||
|
|
||||||
|
if (action.restBetweenSets != null && i < action.totalSets - 1) {
|
||||||
|
totalItems += 1;
|
||||||
|
items.add(Rest(
|
||||||
|
id: totalItems,
|
||||||
|
position: totalItems,
|
||||||
|
action: action,
|
||||||
|
time: action.restBetweenSets!,
|
||||||
|
name: 'rest'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.restAfterSets != null && totalItems != items.length) {
|
||||||
|
totalItems += 1;
|
||||||
|
items.add(Rest(
|
||||||
|
id: totalItems,
|
||||||
|
position: totalItems,
|
||||||
|
action: action,
|
||||||
|
time: action.restAfterSets!,
|
||||||
|
name: 'rest'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Action> updateStatus(ActionStatus status) async {
|
||||||
|
Action newAction = action.copyWith(id: action.id, status: status);
|
||||||
|
await dao.createOrUpdate(newAction.toCompanion(true));
|
||||||
|
action = newAction;
|
||||||
|
return newAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Action> updateState(String state) async {
|
||||||
|
Action newAction = action.copyWith(id: action.id, state: state);
|
||||||
|
await dao.createOrUpdate(newAction.toCompanion(true));
|
||||||
|
action = newAction;
|
||||||
|
return newAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Item {
|
||||||
|
final int id;
|
||||||
|
final Action action;
|
||||||
|
int position;
|
||||||
|
List<Item> items = [];
|
||||||
|
dynamic value;
|
||||||
|
final String name;
|
||||||
|
int? parentId;
|
||||||
|
int? time;
|
||||||
|
|
||||||
|
Item(
|
||||||
|
{required this.id,
|
||||||
|
required this.position,
|
||||||
|
required this.action,
|
||||||
|
this.parentId,
|
||||||
|
this.time})
|
||||||
|
: name = action.title;
|
||||||
|
|
||||||
|
RepType get valueType => action.repType;
|
||||||
|
String get humanValueType => valueType == RepType.time ? 'seconds' : 'reps';
|
||||||
|
}
|
||||||
|
|
||||||
|
class Set extends Item {
|
||||||
|
final int totalReps;
|
||||||
|
int? setOrder;
|
||||||
|
|
||||||
|
Set(
|
||||||
|
{required super.id,
|
||||||
|
required super.action,
|
||||||
|
required super.position,
|
||||||
|
required this.totalReps,
|
||||||
|
this.setOrder}) {
|
||||||
|
items = _generateItems(action, id, totalReps);
|
||||||
|
}
|
||||||
|
|
||||||
|
int? get weightMultiplyer =>
|
||||||
|
action.setWeights != null ? json.decode(action.setWeights!)[id] : null;
|
||||||
|
List<Reps> get reps => items.whereType<Reps>().toList();
|
||||||
|
|
||||||
|
static List<Item> _generateItems(action, id, totalReps) {
|
||||||
|
List<Item> items = [];
|
||||||
|
// add item for exercise
|
||||||
|
int position = 0;
|
||||||
|
|
||||||
|
if (action.repType == RepType.time) {
|
||||||
|
for (int i = 0; i < totalReps; i++) {
|
||||||
|
position = position > 0 ? position + 1 : position;
|
||||||
|
items.add(Reps(
|
||||||
|
id: position, position: position, parentId: id, action: action));
|
||||||
|
|
||||||
|
if (action.isAlternating) {
|
||||||
|
items.add(Rest(
|
||||||
|
id: ++position,
|
||||||
|
position: position,
|
||||||
|
parentId: id,
|
||||||
|
action: action,
|
||||||
|
time: action.restBetweenReps,
|
||||||
|
name: 'alternate'));
|
||||||
|
items.add(Reps(
|
||||||
|
id: ++position,
|
||||||
|
position: position,
|
||||||
|
parentId: id,
|
||||||
|
action: action));
|
||||||
|
|
||||||
|
// don't show a rest after the last rep
|
||||||
|
if (i < totalReps - 1) {
|
||||||
|
items.add(Rest(
|
||||||
|
id: ++position,
|
||||||
|
position: position,
|
||||||
|
parentId: id,
|
||||||
|
action: action,
|
||||||
|
time: action.restBetweenReps,
|
||||||
|
name: 'prepare'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items.add(Reps(id: id, position: position, action: action));
|
||||||
|
|
||||||
|
if (action.isAlternating) {
|
||||||
|
items.add(Rest(
|
||||||
|
id: ++position,
|
||||||
|
position: position,
|
||||||
|
parentId: id,
|
||||||
|
action: action,
|
||||||
|
time: action.restBetweenReps,
|
||||||
|
name: 'alternate'));
|
||||||
|
items.add(Reps(id: id, position: ++position, action: action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Reps extends Item {
|
||||||
|
Reps(
|
||||||
|
{required super.id,
|
||||||
|
required super.position,
|
||||||
|
required super.action,
|
||||||
|
super.parentId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic get value => type == RepType.time ? time : count;
|
||||||
|
|
||||||
|
RepType get type => action.repType;
|
||||||
|
@override
|
||||||
|
int? get time => toSeconds(action.repLength!);
|
||||||
|
int? get count => getReps(id, json.decode(action.totalReps));
|
||||||
|
int? get weight =>
|
||||||
|
action.repWeights != null ? json.decode(action.repWeights!)[id] : null;
|
||||||
|
|
||||||
|
static int getReps(setId, reps) {
|
||||||
|
if (reps.length > 1) {
|
||||||
|
return reps[setId];
|
||||||
|
} else {
|
||||||
|
return reps.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rest extends Item {
|
||||||
|
@override
|
||||||
|
String name;
|
||||||
|
|
||||||
|
Rest(
|
||||||
|
{required super.id,
|
||||||
|
required super.position,
|
||||||
|
required super.action,
|
||||||
|
super.parentId,
|
||||||
|
required super.time,
|
||||||
|
required this.name});
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// String get name => 'Rest';
|
||||||
|
@override
|
||||||
|
int get value => toSeconds(time ?? 0);
|
||||||
|
@override
|
||||||
|
RepType get valueType => RepType.time;
|
||||||
|
}
|
173
lib/providers/action_timer.dart
Normal file
173
lib/providers/action_timer.dart
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
import 'package:sendtrain/database/database.dart';
|
||||||
|
import 'package:sendtrain/models/action_model.dart';
|
||||||
|
|
||||||
|
class ActionTimer with ChangeNotifier {
|
||||||
|
ActionModel? actionModel;
|
||||||
|
double _progress = 0;
|
||||||
|
int _currentTime = 0;
|
||||||
|
final List<ItemScrollController> _scrollControllers = [];
|
||||||
|
|
||||||
|
ActionTimer();
|
||||||
|
|
||||||
|
Map get state => actionModel?.state ?? _stateConstructor();
|
||||||
|
ActionStatus get status => actionModel?.status ?? ActionStatus.pending;
|
||||||
|
bool get started => status == ActionStatus.started;
|
||||||
|
bool get paused => status == ActionStatus.paused;
|
||||||
|
bool get pending => status == ActionStatus.pending;
|
||||||
|
bool get complete => status == ActionStatus.complete;
|
||||||
|
bool get available => paused | pending;
|
||||||
|
List<Set> get sets => actionModel!.sets;
|
||||||
|
List<Item> get items => actionModel!.items;
|
||||||
|
Set get currentSet => sets[state['currentSet']];
|
||||||
|
Reps get currentRep => currentSet.reps[state['currentRep']];
|
||||||
|
Item get currentAction => allActions[state['currentAction']];
|
||||||
|
int get currentTime => _currentTime;
|
||||||
|
dynamic get currentValue => currentAction.valueType == RepType.time
|
||||||
|
? currentTime
|
||||||
|
: currentAction.value;
|
||||||
|
List<Item> get allActions => actionModel?.allItems ?? [];
|
||||||
|
String get repType =>
|
||||||
|
actionModel!.action.repType == RepType.time ? 'Seconds' : 'Reps';
|
||||||
|
int? get repLength => currentRep.value;
|
||||||
|
int? get repCount => currentRep.count;
|
||||||
|
dynamic get repValue =>
|
||||||
|
actionModel!.action.repType == RepType.time ? repLength : repCount;
|
||||||
|
double get progress => _progress;
|
||||||
|
int get totalTime => actionModel!.totalTime;
|
||||||
|
Timer? _periodicTimer;
|
||||||
|
|
||||||
|
Map _stateConstructor() {
|
||||||
|
return {
|
||||||
|
'currentSet': 0,
|
||||||
|
'currentRep': 0,
|
||||||
|
'currentTime': 0,
|
||||||
|
'currentAction': 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(ActionModel actionModel, ItemScrollController scrollController,
|
||||||
|
[bool resetOnLoad = true]) {
|
||||||
|
if (resetOnLoad) {
|
||||||
|
if (this.actionModel == actionModel) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actionModel = actionModel;
|
||||||
|
setAction(currentAction.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
_scrollControllers.add(scrollController);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future pause() async =>
|
||||||
|
await actionModel?.updateStatus(ActionStatus.paused).whenComplete(() {
|
||||||
|
_periodicTimer?.cancel();
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
|
||||||
|
Future start() async {
|
||||||
|
await actionModel!.updateStatus(ActionStatus.started);
|
||||||
|
|
||||||
|
// start timer
|
||||||
|
if (_periodicTimer == null || _periodicTimer!.isActive == false) {
|
||||||
|
_periodicTimer =
|
||||||
|
Timer.periodic(const Duration(seconds: 1), (Timer timer) async {
|
||||||
|
switch (currentAction.valueType) {
|
||||||
|
case RepType.count:
|
||||||
|
break;
|
||||||
|
case RepType.time:
|
||||||
|
_currentTime--;
|
||||||
|
|
||||||
|
if (_currentTime == 0) {
|
||||||
|
// move to next action
|
||||||
|
await setAction(state['currentAction'] + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateProgress();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future close() async =>
|
||||||
|
await actionModel!.updateStatus(ActionStatus.complete).whenComplete(() {
|
||||||
|
_periodicTimer!.cancel();
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
|
||||||
|
Future reset() async {
|
||||||
|
await actionModel!.updateStatus(ActionStatus.pending);
|
||||||
|
await actionModel!.updateState(json.encode(_stateConstructor()));
|
||||||
|
_periodicTimer?.cancel();
|
||||||
|
_progress = 0;
|
||||||
|
_scrollControllers.clear();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future clear() async {
|
||||||
|
await reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeUsed() {
|
||||||
|
Iterable<Item> usedItems = allActions.getRange(0, state['currentAction']);
|
||||||
|
return usedItems.fold(0.0, (p, c) => p + c.value!);
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalComplete() {
|
||||||
|
Iterable<Item> usedItems = allActions.getRange(0, state['currentAction']);
|
||||||
|
return usedItems.length / allActions.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress() {
|
||||||
|
double repUsed = (currentAction.value - currentTime) / currentAction.value;
|
||||||
|
_progress =
|
||||||
|
totalComplete() + ((repUsed < 0 ? 0 : repUsed) / allActions.length);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
setAction(int actionNum, [bool isManual = false]) async {
|
||||||
|
Item item = allActions[actionNum];
|
||||||
|
Map newState = state;
|
||||||
|
|
||||||
|
newState['currentAction'] = actionNum;
|
||||||
|
newState['currentSet'] = item.parentId;
|
||||||
|
newState['currentRep'] = item.id;
|
||||||
|
newState['currentTime'] = _currentTime = item.value!;
|
||||||
|
|
||||||
|
await actionModel!
|
||||||
|
.updateState(json.encode(newState))
|
||||||
|
.whenComplete(() async {
|
||||||
|
if (isManual) {
|
||||||
|
await pause();
|
||||||
|
await updateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = currentAction.parentId != null
|
||||||
|
? currentAction.parentId!
|
||||||
|
: currentAction.id;
|
||||||
|
|
||||||
|
for (int i = 0; i < _scrollControllers.length; i++) {
|
||||||
|
ItemScrollController sc = _scrollControllers[i];
|
||||||
|
|
||||||
|
sc.scrollTo(
|
||||||
|
index: index,
|
||||||
|
duration: Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOutCubic);
|
||||||
|
}
|
||||||
|
// _scrollController?.scrollTo(
|
||||||
|
// index: index,
|
||||||
|
// duration: Duration(milliseconds: 500),
|
||||||
|
// curve: Curves.easeInOutCubic);
|
||||||
|
});
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
39
lib/widgets/activities/activity_action_editor.dart
Normal file
39
lib/widgets/activities/activity_action_editor.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart' hide Action;
|
||||||
|
import 'package:sendtrain/database/database.dart';
|
||||||
|
import 'package:sendtrain/widgets/generic/elements/form_text_input.dart';
|
||||||
|
|
||||||
|
class ActivityActionEditor extends StatelessWidget {
|
||||||
|
ActivityActionEditor({super.key, required this.action, this.callback});
|
||||||
|
|
||||||
|
final Action action;
|
||||||
|
final Function? callback;
|
||||||
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final Map<String, TextEditingController> actionEditController = {
|
||||||
|
'sets': TextEditingController(),
|
||||||
|
'reps': TextEditingController(),
|
||||||
|
'weight': TextEditingController(),
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
String editorType = 'Create';
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(15, 0, 15, 15),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 10, bottom: 10),
|
||||||
|
child: Text('$editorType Action',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge)),
|
||||||
|
FormTextInput(
|
||||||
|
controller: actionEditController['sets']!,
|
||||||
|
title: 'Total Sets'),])));
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,26 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
import 'package:sendtrain/database/database.dart';
|
||||||
import 'package:sendtrain/extensions/string_extensions.dart';
|
import 'package:sendtrain/extensions/string_extensions.dart';
|
||||||
import 'package:sendtrain/models/activity_timer_model.dart';
|
import 'package:sendtrain/models/action_model.dart';
|
||||||
|
import 'package:sendtrain/providers/action_timer.dart';
|
||||||
|
import 'package:sendtrain/widgets/generic/elements/add_card_generic.dart';
|
||||||
|
|
||||||
class ActivityActionView extends StatefulWidget {
|
class ActivityActionView extends StatefulWidget {
|
||||||
const ActivityActionView({super.key, required this.actions});
|
const ActivityActionView({super.key, required this.actions, this.resetOnLoad = true});
|
||||||
final List actions;
|
final List actions;
|
||||||
|
final bool resetOnLoad;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ActivityActionView> createState() => ActivityActionViewState();
|
State<ActivityActionView> createState() => ActivityActionViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActivityActionViewState extends State<ActivityActionView> {
|
class ActivityActionViewState extends State<ActivityActionView> {
|
||||||
|
// class ActivityActionView extends StatelessWidget {
|
||||||
|
// ActivityActionView({super.key, required this.actions});
|
||||||
|
|
||||||
|
// final List actions;
|
||||||
final ItemScrollController itemScrollController = ItemScrollController();
|
final ItemScrollController itemScrollController = ItemScrollController();
|
||||||
final ScrollOffsetController scrollOffsetController =
|
final ScrollOffsetController scrollOffsetController =
|
||||||
ScrollOffsetController();
|
ScrollOffsetController();
|
||||||
@ -23,64 +29,167 @@ class ActivityActionViewState extends State<ActivityActionView> {
|
|||||||
final ScrollOffsetListener scrollOffsetListener =
|
final ScrollOffsetListener scrollOffsetListener =
|
||||||
ScrollOffsetListener.create();
|
ScrollOffsetListener.create();
|
||||||
|
|
||||||
@override
|
late final ActionTimer at;
|
||||||
Widget build(BuildContext context) {
|
int actionCount = 0;
|
||||||
ActivityTimerModel atm =
|
|
||||||
Provider.of<ActivityTimerModel>(context, listen: true);
|
|
||||||
List sets = json.decode(widget.actions[0].set);
|
|
||||||
|
|
||||||
// we need to set the scroll controller
|
GestureDetector gtBuild(
|
||||||
// so we can update the selected item position
|
ActionTimer at, Item item, int actionNum, int selectedIndex,
|
||||||
atm.setScrollController(itemScrollController);
|
{int? order}) {
|
||||||
|
// default, for rests
|
||||||
|
String setItemRef = '-';
|
||||||
|
|
||||||
return Expanded(
|
// non rests decimal reference to item
|
||||||
child: ScrollablePositionedList.builder(
|
if (order != null) {
|
||||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 20),
|
setItemRef = '${order + 1}.${item.position + 1}';
|
||||||
itemCount: sets.length,
|
}
|
||||||
itemScrollController: itemScrollController,
|
|
||||||
scrollOffsetController: scrollOffsetController,
|
|
||||||
itemPositionsListener: itemPositionsListener,
|
|
||||||
scrollOffsetListener: scrollOffsetListener,
|
|
||||||
itemBuilder: (BuildContext context, int setNum) {
|
|
||||||
List<GestureDetector> content = [];
|
|
||||||
List set = sets[setNum];
|
|
||||||
|
|
||||||
for (int actionNum = 0; actionNum < set.length; actionNum++) {
|
return GestureDetector(onTap: () {
|
||||||
Map<String, dynamic> setItem = set[actionNum];
|
at.setAction(actionNum, true);
|
||||||
|
}, child: Consumer<ActionTimer>(builder: (context, at, child) {
|
||||||
content.add(GestureDetector(
|
return Row(children: [
|
||||||
onTap: () {
|
|
||||||
atm.setAction(setNum, actionNum, 'manual');
|
|
||||||
atm.setActionCount();
|
|
||||||
|
|
||||||
itemScrollController.scrollTo(
|
|
||||||
index: setNum,
|
|
||||||
duration: Duration(milliseconds: 500),
|
|
||||||
curve: Curves.easeInOutCubic);
|
|
||||||
},
|
|
||||||
child: Row(children: [
|
|
||||||
Ink(
|
Ink(
|
||||||
width: 70,
|
width: 70,
|
||||||
padding: const EdgeInsets.all(15),
|
padding: const EdgeInsets.all(15),
|
||||||
color: atm.isCurrentItem(setNum, actionNum)
|
color: item == at.currentAction
|
||||||
? Theme.of(context).colorScheme.primaryContainer
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
: Theme.of(context).colorScheme.onPrimary,
|
: Theme.of(context).colorScheme.onPrimary,
|
||||||
child: Text(
|
child: Text(textAlign: TextAlign.center, setItemRef)),
|
||||||
textAlign: TextAlign.center,
|
|
||||||
'${setNum + 1}.${actionNum + 1} ')),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Ink(
|
child: Ink(
|
||||||
padding: const EdgeInsets.all(15),
|
padding: const EdgeInsets.all(15),
|
||||||
color: atm.isCurrentItem(setNum, actionNum)
|
color: item == at.currentAction
|
||||||
? Theme.of(context).colorScheme.surfaceBright
|
? Theme.of(context).colorScheme.surfaceBright
|
||||||
: Theme.of(context).colorScheme.surfaceContainerLow,
|
: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
child: Text(
|
child: Text(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
'${setItem['name']}: ${setItem['amount']} ${setItem['type']}'.toTitleCase())))
|
'${item.name}: ${item.value} ${item.humanValueType}'
|
||||||
])));
|
.toTitleCase())))
|
||||||
|
]);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setNum == 0) {
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
at = Provider.of<ActionTimer>(context, listen: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.actions.isNotEmpty) {
|
||||||
|
at.setup(ActionModel(
|
||||||
|
action: widget.actions.first, db: Provider.of<AppDatabase>(context)), itemScrollController, widget.resetOnLoad);
|
||||||
|
|
||||||
|
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
// if (itemScrollController.isAttached) {
|
||||||
|
// itemScrollController.scrollTo(
|
||||||
|
// index: at.currentAction.parentId != null
|
||||||
|
// ? at.currentAction.parentId!
|
||||||
|
// : at.currentAction.id,
|
||||||
|
// duration: Duration(milliseconds: 500),
|
||||||
|
// curve: Curves.easeInOutCubic);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
return Expanded(
|
||||||
|
child: Column(children: [
|
||||||
|
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<ActionTimer>(
|
||||||
|
builder: (context, at, child) {
|
||||||
|
return IconButton(
|
||||||
|
alignment: AlignmentDirectional.center,
|
||||||
|
icon: at.available
|
||||||
|
? const Icon(Icons.play_arrow_rounded)
|
||||||
|
: const Icon(Icons.pause_rounded),
|
||||||
|
onPressed: () => {
|
||||||
|
if (at.started)
|
||||||
|
{at.pause()}
|
||||||
|
else if (at.available)
|
||||||
|
{at.start()}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Stack(alignment: Alignment.center, children: [
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Consumer<ActionTimer>(
|
||||||
|
builder: (context, at, child) {
|
||||||
|
return Text(
|
||||||
|
style: const TextStyle(fontSize: 20),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
'${at.currentValue} ${at.currentAction.humanValueType}'
|
||||||
|
.toTitleCase());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
padding: EdgeInsets.only(right: 15),
|
||||||
|
child: Consumer<ActionTimer>(
|
||||||
|
builder: (context, at, child) {
|
||||||
|
return Text(
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
'${at.state['currentAction'] + 1} of ${at.allActions.length}');
|
||||||
|
})),
|
||||||
|
])),
|
||||||
|
]))),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 14, right: 14),
|
||||||
|
child: Consumer<ActionTimer>(builder: (context, at, child) {
|
||||||
|
return LinearProgressIndicator(
|
||||||
|
value: at.progress,
|
||||||
|
semanticsLabel: 'Activity Progress',
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
Expanded(
|
||||||
|
child: ScrollablePositionedList.builder(
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 20),
|
||||||
|
itemCount: at.items.length,
|
||||||
|
// initialScrollIndex: at.currentAction.parentId != null
|
||||||
|
// ? at.currentAction.parentId!
|
||||||
|
// : at.currentAction.id,
|
||||||
|
itemScrollController: itemScrollController,
|
||||||
|
scrollOffsetController: scrollOffsetController,
|
||||||
|
itemPositionsListener: itemPositionsListener,
|
||||||
|
scrollOffsetListener: scrollOffsetListener,
|
||||||
|
itemBuilder: (BuildContext context, int itemNum) {
|
||||||
|
if (itemNum == 0) {
|
||||||
|
actionCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GestureDetector> content = [];
|
||||||
|
Item item = at.items[itemNum];
|
||||||
|
if (item.runtimeType == Rest) {
|
||||||
|
content.add(gtBuild(at, item, actionCount++, itemNum));
|
||||||
|
} else if (item.runtimeType == Set) {
|
||||||
|
List<Item> setItems = item.items;
|
||||||
|
|
||||||
|
for (int setItemNum = 0;
|
||||||
|
setItemNum < setItems.length;
|
||||||
|
setItemNum++) {
|
||||||
|
Item setItem = setItems[setItemNum];
|
||||||
|
content.add(gtBuild(at, setItem, actionCount++, itemNum,
|
||||||
|
order: (item as Set).setOrder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemNum == 0) {
|
||||||
return Card(
|
return Card(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
@ -103,8 +212,16 @@ class ActivityActionViewState extends State<ActivityActionView> {
|
|||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Column(children: content));
|
child: Column(children: content));
|
||||||
}
|
}
|
||||||
// return Column(children: contents);
|
}))
|
||||||
},
|
]));
|
||||||
));
|
} else {
|
||||||
|
return AddCardGeneric(
|
||||||
|
title: 'Add an Action!',
|
||||||
|
description:
|
||||||
|
'Click here to create an exercise template (sets and reps, etc) for your activity!',
|
||||||
|
action: () {
|
||||||
|
print('teset');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart' hide Action;
|
||||||
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:sendtrain/daos/actions_dao.dart';
|
import 'package:sendtrain/daos/actions_dao.dart';
|
||||||
import 'package:sendtrain/database/database.dart';
|
import 'package:sendtrain/database/database.dart';
|
||||||
import 'package:sendtrain/extensions/string_extensions.dart';
|
import 'package:sendtrain/extensions/string_extensions.dart';
|
||||||
import 'package:sendtrain/helpers/widget_helpers.dart';
|
import 'package:sendtrain/helpers/widget_helpers.dart';
|
||||||
import 'package:sendtrain/models/activity_timer_model.dart';
|
import 'package:sendtrain/widgets/activities/activity_action_editor.dart';
|
||||||
import 'package:sendtrain/widgets/activities/activity_action_view.dart';
|
import 'package:sendtrain/widgets/activities/activity_action_view.dart';
|
||||||
import 'package:sendtrain/widgets/activities/activity_view_categories.dart';
|
import 'package:sendtrain/widgets/activities/activity_view_categories.dart';
|
||||||
import 'package:sendtrain/widgets/activities/activity_view_media.dart';
|
import 'package:sendtrain/widgets/activities/activity_view_media.dart';
|
||||||
import 'package:sendtrain/widgets/generic/elements/add_card_generic.dart';
|
import 'package:sendtrain/widgets/builders/dialogs.dart';
|
||||||
|
|
||||||
class ActivityView extends StatefulWidget {
|
class ActivityView extends StatefulWidget {
|
||||||
const ActivityView({super.key, required this.activity});
|
const ActivityView({super.key, required this.activity});
|
||||||
@ -22,7 +22,7 @@ class ActivityView extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ActivityViewState extends State<ActivityView> {
|
class _ActivityViewState extends State<ActivityView> {
|
||||||
List<ActivityMuscle> activity_muscle(Activity activity) {
|
List<ActivityMuscle> activityMuscle(Activity activity) {
|
||||||
List<ActivityMuscle> muscles = [];
|
List<ActivityMuscle> muscles = [];
|
||||||
|
|
||||||
if (activity.primaryMuscles != null) {
|
if (activity.primaryMuscles != null) {
|
||||||
@ -36,99 +36,29 @@ class _ActivityViewState extends State<ActivityView> {
|
|||||||
return muscles;
|
return muscles;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> action(actions) {
|
|
||||||
if (actions.isNotEmpty) {
|
|
||||||
return [
|
|
||||||
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']}'
|
|
||||||
.toTitleCase());
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
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(actions: actions)
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
AddCardGeneric(
|
|
||||||
title: 'Add an Action!',
|
|
||||||
description:
|
|
||||||
'Click here to create an exercise template (sets and reps, etc) for your activity!',
|
|
||||||
action: () {
|
|
||||||
print('teset');
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Activity activity = widget.activity;
|
final Activity activity = widget.activity;
|
||||||
ActivityTimerModel atm =
|
|
||||||
Provider.of<ActivityTimerModel>(context, listen: false);
|
|
||||||
|
|
||||||
return FutureBuilder<List>(
|
return FutureBuilder<List>(
|
||||||
future: ActionsDao(Provider.of<AppDatabase>(context))
|
future: ActionsDao(Provider.of<AppDatabase>(context))
|
||||||
.fromActivity(activity),
|
.fromActivity(activity),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
List actions = snapshot.data!;
|
List<Action> actions = snapshot.data! as List<Action>;
|
||||||
atm.setup(activity, actions);
|
|
||||||
|
|
||||||
return Scaffold(
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvokedWithResult: (didPop, result) async {
|
||||||
|
if (didPop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final bool shouldPop = await showBackDialog(context) ?? false;
|
||||||
|
if (context.mounted && shouldPop) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
floatingActionButtonLocation: ExpandableFab.location,
|
floatingActionButtonLocation: ExpandableFab.location,
|
||||||
floatingActionButton: ExpandableFab(
|
floatingActionButton: ExpandableFab(
|
||||||
distance: 70,
|
distance: 70,
|
||||||
@ -143,6 +73,16 @@ class _ActivityViewState extends State<ActivityView> {
|
|||||||
// label: Text('Upload Media'),
|
// label: Text('Upload Media'),
|
||||||
// onPressed: () {},
|
// onPressed: () {},
|
||||||
// ),
|
// ),
|
||||||
|
FloatingActionButton.extended(
|
||||||
|
icon: const Icon(Icons.done_all_outlined),
|
||||||
|
label: Text('Edit Action'),
|
||||||
|
onPressed: () {
|
||||||
|
showEditorSheet(
|
||||||
|
context,
|
||||||
|
ActivityActionEditor(
|
||||||
|
action: actions.first, callback: () {}));
|
||||||
|
},
|
||||||
|
),
|
||||||
FloatingActionButton.extended(
|
FloatingActionButton.extended(
|
||||||
icon: const Icon(Icons.note_add_outlined),
|
icon: const Icon(Icons.note_add_outlined),
|
||||||
label: Text('Add Note'),
|
label: Text('Add Note'),
|
||||||
@ -215,7 +155,7 @@ class _ActivityViewState extends State<ActivityView> {
|
|||||||
List<ActivityMuscle>>(
|
List<ActivityMuscle>>(
|
||||||
icon: Icon(Icons.person),
|
icon: Icon(Icons.person),
|
||||||
text: 'Muscles used',
|
text: 'Muscles used',
|
||||||
object: activity_muscle(activity))
|
object: activityMuscle(activity))
|
||||||
])),
|
])),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
@ -272,16 +212,35 @@ class _ActivityViewState extends State<ActivityView> {
|
|||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
'Media:')),
|
'Media:')),
|
||||||
ActivityViewMedia(activity: activity),
|
ActivityViewMedia(activity: activity),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.fromLTRB(15, 30, 0, 10),
|
padding: const EdgeInsets.fromLTRB(15, 20, 5, 0),
|
||||||
child: Text(
|
child: Row(children: [
|
||||||
|
Expanded(
|
||||||
|
child: const Text(
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
'Actions')),
|
'Actions')),
|
||||||
] +
|
IconButton(
|
||||||
action(actions)));
|
onPressed: () {
|
||||||
|
showGenericSheet(
|
||||||
|
context,
|
||||||
|
Column(children: [
|
||||||
|
ActivityActionView(
|
||||||
|
actions: actions,
|
||||||
|
resetOnLoad: false)
|
||||||
|
]),
|
||||||
|
Theme.of(context).colorScheme.surface);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.expand),
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
)
|
||||||
|
])),
|
||||||
|
ActivityActionView(actions: actions)
|
||||||
|
])));
|
||||||
|
// ] +
|
||||||
|
// action(actions, context)));
|
||||||
} else {
|
} else {
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sendtrain/providers/action_timer.dart';
|
||||||
|
|
||||||
Future showGenericDialog(dynamic object, BuildContext parentContext) {
|
Future showGenericDialog(dynamic object, BuildContext parentContext) {
|
||||||
return showGeneralDialog(
|
return showGeneralDialog(
|
||||||
@ -55,3 +57,51 @@ Future showUpdateDialog(String title, String content, BuildContext context,
|
|||||||
[Function? callback]) {
|
[Function? callback]) {
|
||||||
return showCrudDialog(title, content, context, callback);
|
return showCrudDialog(title, content, context, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - factor out, this should be more generic
|
||||||
|
Future<bool?> showBackDialog(BuildContext context) async {
|
||||||
|
ActionTimer at = Provider.of<ActionTimer>(context, listen: false);
|
||||||
|
|
||||||
|
if (at.pending || at.complete) {
|
||||||
|
await at.clear();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Are you sure?'),
|
||||||
|
content: const Text(
|
||||||
|
'Leaving will stop the current activity. Are you sure you want to leave?',
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Nevermind'),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context, false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Leave'),
|
||||||
|
onPressed: () async {
|
||||||
|
ActionTimer at =
|
||||||
|
Provider.of<ActionTimer>(context, listen: false);
|
||||||
|
await at.clear();
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -82,6 +82,7 @@ class _FormSearchInputState extends State<FormSearchInput> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SearchAnchor(
|
return SearchAnchor(
|
||||||
|
isFullScreen: false,
|
||||||
builder: (BuildContext context, SearchController controller) {
|
builder: (BuildContext context, SearchController controller) {
|
||||||
return FormTextInput(
|
return FormTextInput(
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
@ -92,7 +93,8 @@ class _FormSearchInputState extends State<FormSearchInput> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
controller.openView();
|
controller.openView();
|
||||||
});
|
});
|
||||||
}, suggestionsBuilder:
|
},
|
||||||
|
suggestionsBuilder:
|
||||||
(BuildContext context, SearchController controller) async {
|
(BuildContext context, SearchController controller) async {
|
||||||
final List<Suggestion>? options =
|
final List<Suggestion>? options =
|
||||||
(await debouncer.process(controller.text))?.toList();
|
(await debouncer.process(controller.text))?.toList();
|
||||||
|
@ -51,6 +51,7 @@ dependencies:
|
|||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
video_player: ^2.9.2
|
video_player: ^2.9.2
|
||||||
dart_casing: ^3.0.1
|
dart_casing: ^3.0.1
|
||||||
|
collection: ^1.18.0
|
||||||
|
|
||||||
flutter_launcher_name:
|
flutter_launcher_name:
|
||||||
name: "SendTrain"
|
name: "SendTrain"
|
||||||
|
@ -25,6 +25,17 @@ import 'schema_v9.dart' as v9;
|
|||||||
import 'schema_v20.dart' as v20;
|
import 'schema_v20.dart' as v20;
|
||||||
import 'schema_v21.dart' as v21;
|
import 'schema_v21.dart' as v21;
|
||||||
import 'schema_v22.dart' as v22;
|
import 'schema_v22.dart' as v22;
|
||||||
|
import 'schema_v23.dart' as v23;
|
||||||
|
import 'schema_v24.dart' as v24;
|
||||||
|
import 'schema_v25.dart' as v25;
|
||||||
|
import 'schema_v26.dart' as v26;
|
||||||
|
import 'schema_v27.dart' as v27;
|
||||||
|
import 'schema_v28.dart' as v28;
|
||||||
|
import 'schema_v29.dart' as v29;
|
||||||
|
import 'schema_v30.dart' as v30;
|
||||||
|
import 'schema_v31.dart' as v31;
|
||||||
|
import 'schema_v32.dart' as v32;
|
||||||
|
import 'schema_v33.dart' as v33;
|
||||||
|
|
||||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||||
@override
|
@override
|
||||||
@ -74,6 +85,28 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
return v21.DatabaseAtV21(db);
|
return v21.DatabaseAtV21(db);
|
||||||
case 22:
|
case 22:
|
||||||
return v22.DatabaseAtV22(db);
|
return v22.DatabaseAtV22(db);
|
||||||
|
case 23:
|
||||||
|
return v23.DatabaseAtV23(db);
|
||||||
|
case 24:
|
||||||
|
return v24.DatabaseAtV24(db);
|
||||||
|
case 25:
|
||||||
|
return v25.DatabaseAtV25(db);
|
||||||
|
case 26:
|
||||||
|
return v26.DatabaseAtV26(db);
|
||||||
|
case 27:
|
||||||
|
return v27.DatabaseAtV27(db);
|
||||||
|
case 28:
|
||||||
|
return v28.DatabaseAtV28(db);
|
||||||
|
case 29:
|
||||||
|
return v29.DatabaseAtV29(db);
|
||||||
|
case 30:
|
||||||
|
return v30.DatabaseAtV30(db);
|
||||||
|
case 31:
|
||||||
|
return v31.DatabaseAtV31(db);
|
||||||
|
case 32:
|
||||||
|
return v32.DatabaseAtV32(db);
|
||||||
|
case 33:
|
||||||
|
return v33.DatabaseAtV33(db);
|
||||||
default:
|
default:
|
||||||
throw MissingSchemaException(version, versions);
|
throw MissingSchemaException(version, versions);
|
||||||
}
|
}
|
||||||
@ -101,6 +134,17 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
|||||||
19,
|
19,
|
||||||
20,
|
20,
|
||||||
21,
|
21,
|
||||||
22
|
22,
|
||||||
|
23,
|
||||||
|
24,
|
||||||
|
25,
|
||||||
|
26,
|
||||||
|
27,
|
||||||
|
28,
|
||||||
|
29,
|
||||||
|
30,
|
||||||
|
31,
|
||||||
|
32,
|
||||||
|
33
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
2669
test/drift/sendtrain/generated/schema_v23.dart
Normal file
2669
test/drift/sendtrain/generated/schema_v23.dart
Normal file
File diff suppressed because it is too large
Load Diff
2670
test/drift/sendtrain/generated/schema_v24.dart
Normal file
2670
test/drift/sendtrain/generated/schema_v24.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v25.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v25.dart
Normal file
File diff suppressed because it is too large
Load Diff
2701
test/drift/sendtrain/generated/schema_v26.dart
Normal file
2701
test/drift/sendtrain/generated/schema_v26.dart
Normal file
File diff suppressed because it is too large
Load Diff
2701
test/drift/sendtrain/generated/schema_v27.dart
Normal file
2701
test/drift/sendtrain/generated/schema_v27.dart
Normal file
File diff suppressed because it is too large
Load Diff
2701
test/drift/sendtrain/generated/schema_v28.dart
Normal file
2701
test/drift/sendtrain/generated/schema_v28.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v29.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v29.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v30.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v30.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v31.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v31.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v32.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v32.dart
Normal file
File diff suppressed because it is too large
Load Diff
2702
test/drift/sendtrain/generated/schema_v33.dart
Normal file
2702
test/drift/sendtrain/generated/schema_v33.dart
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user