Skip to content

Commit

Permalink
Convert custom Either wrapper to just an Either
Browse files Browse the repository at this point in the history
  • Loading branch information
ashuntu committed Dec 17, 2024
1 parent f14f632 commit eca7d00
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ class SubscribeNowModel extends ChangeNotifier {
final AgentApiClient client;
P4wMsStore store;

final _token = ProTokenValue();
ProTokenValue get token => _token;
bool get canSubmit => token.token != null;
Either<TokenError, ProToken?> _token = const Either.left(TokenError.empty);
ProToken? get token => _token.orNull();
TokenError? get tokenError =>
_token.fold(ifLeft: (e) => e, ifRight: (_) => null);
bool get canSubmit => token != null;

/// Returns true if the environment variable 'UP4W_ALLOW_STORE_PURCHASE' has been set.
/// Since this reading won't change during the app lifetime, even if the user changes
Expand Down Expand Up @@ -52,29 +54,13 @@ class SubscribeNowModel extends ChangeNotifier {
}
}

void tokenUpdate(String token) async {
_token.update(token);
void updateToken(String raw) {
_token = ProToken.create(raw);
notifyListeners();
}
}

/// A [ProToken] with validation.
///
/// Similar to a [EitherValueNotifier], without the [ValueNotifier].
class ProTokenValue {
ProTokenValue() : either = const Either.left(TokenError.empty);

Either<TokenError, ProToken?> either;
ProToken? get token => either.orNull();
String? get value => either.orNull()?.value;
TokenError? get error => either.fold(ifLeft: (e) => e, ifRight: (_) => null);
bool get hasError => either.isLeft;

void update(String token) {
either = ProToken.create(token);
}

void clear() {
either = const Either.right(null);
void clearToken() {
_token = const Either.right(null);
notifyListeners();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ class SubscribeNowPage extends StatelessWidget {
}

void trySubmit(SubscribeNowModel model) {
model.applyProToken(model.token.token!).then(onSubscriptionUpdate);
model.token.clear();
model.applyProToken(model.token!).then(onSubscriptionUpdate);
model.clearToken();
controller.clear();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@ class ProTokenInputField extends StatelessWidget {
controller: controller,
decoration: InputDecoration(
label: Text(lang.tokenInputHint),
error: model.token.error?.localize(lang) != null
error: model.tokenError?.localize(lang) != null
? Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
model.token.error!.localize(lang)!,
model.tokenError!.localize(lang)!,
style: theme.textTheme.bodySmall!.copyWith(
color: YaruColors.of(context).error,
),
),
)
: null,
),
onChanged: model.tokenUpdate,
onChanged: model.updateToken,
onSubmitted: (_) => onSubmit?.call(),
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,37 @@ import 'subscribe_now_model_test.mocks.dart';

@GenerateMocks([AgentApiClient])
void main() {
group('token', () {
final client = MockAgentApiClient();

test('errors', () async {
final model = SubscribeNowModel(client);
expect(model.canSubmit, isFalse);

model.updateToken('');
expect(model.token, isNull);
expect(model.tokenError, TokenError.empty);
expect(model.canSubmit, isFalse);

for (final badToken in tks.invalidTokens) {
model.updateToken(badToken);
expect(model.token, isNull);
expect(model.tokenError, TokenError.invalid);
expect(model.canSubmit, isFalse);
}
});

test('valid', () async {
final model = SubscribeNowModel(client);
expect(model.canSubmit, isFalse);

model.updateToken(tks.good);
expect(model.token, isNotNull);
expect(model.tokenError, isNull);
expect(model.canSubmit, isTrue);
});
});

group('purchase', () {
const pluginChannel = MethodChannelP4wMsStore.methodChannel;
final pluginMessenger =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,6 @@ void main() {
expect(launcher.launched, isTrue);
});

group('pro token value', () {
test('errors', () async {
final value = ProTokenValue();

value.update('');
expect(value.error, TokenError.empty);

for (final token in tks.invalidTokens) {
value.update(token);
expect(value.error, TokenError.invalid);
}
});
test('accessors on success', () {
final value = ProTokenValue();
final tokenInstance = ProToken.create(tks.good).orNull();

value.update(tks.good);

expect(value.hasError, isFalse);
expect(value.error, isNull);
expect(value.value, tks.good);
expect(value.value, tks.good);
expect(value.token, tokenInstance);
expect(value.either, equals(ProToken.create(tks.good)));
});
});

group('pro token input', () {
group('basic flow', () {
final theApp = buildApp(onApply: () {}, isExpanded: true);
Expand Down

0 comments on commit eca7d00

Please sign in to comment.