Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ToB][Frontend] Save user code #25298

Closed
wants to merge 130 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
7c23033
Content tree navigation (#23593)
Oct 21, 2022
5978d37
AnimatedBuilders instead of StatefulWidgets in unit & group (#23593)
Nov 4, 2022
8807c00
fixed _getNodeAncestors (#23593)
Nov 5, 2022
8e8d8c9
get sdkId (#23593)
Nov 5, 2022
2ab4b3b
addressing comments (#23593)
Nov 8, 2022
57800ee
sdkId getter & StatelessExpansionTile (#23593)
Nov 9, 2022
28cb6b8
expand & collapse group (#23593)
Nov 9, 2022
85e1234
StatelessExpansionTile (#23593)
Nov 9, 2022
8dc7719
license (#23593)
Nov 10, 2022
e4dee7b
ValueChanged and ValueKey in StatelessExpansionTile (#23593)
Nov 11, 2022
5b07e91
optional SDK selector in tour scaffold
Nov 14, 2022
497ff7c
AppNotifier
Nov 14, 2022
83c9c0e
moved AppNotifier into _initializeState
Nov 15, 2022
9d1f49b
StorageKeys
Nov 15, 2022
b78bbd3
remove listener
Nov 16, 2022
5297d25
auth, complete unit, user progress
Oct 19, 2022
d25eaf5
Merge branch 'master' into issue23692_auth
nausharipov Nov 18, 2022
12a685d
unit file fix
Nov 18, 2022
3c534d8
Merge remote-tracking branch 'origin/tour-header-sdk-selector' into a…
nausharipov Nov 18, 2022
de0f7c3
sdk selection works with auth
Nov 18, 2022
3a10e8d
show sdk selector in welcome screen
Nov 18, 2022
de273ba
hide back button after navigating from welcome
Nov 18, 2022
70c0d61
comments (0)
Nov 19, 2022
6f53e30
cache license
Nov 21, 2022
4aedd5a
SDK selector with fixed comments
Nov 21, 2022
5ad067f
non-nullable onChanged
Nov 21, 2022
10b287b
Merge pull request #324 from akvelon/tour-header-sdk-selector
nausharipov Nov 21, 2022
a6597d4
untested refinement
Nov 21, 2022
2068ce9
deleted show sdk selector
Nov 21, 2022
52838e5
notifier objects naming
Nov 21, 2022
3df27bc
untested refinement (1)
Nov 22, 2022
0b6fc8f
candidate repository
Nov 22, 2022
7fbaf38
new configs & todos
Nov 23, 2022
64965a1
canCompleteCurrentUnit (#23692)
Nov 24, 2022
6d21e1e
kOpenLoginOverlay (#23692)
Nov 24, 2022
2c90ced
login_overlay (#23692)
Nov 24, 2022
6ed38ac
unused import (#23692)
Nov 24, 2022
adbdeb6
deleted file (#23692)
Nov 24, 2022
c2f74a5
review comments (2)
Nov 27, 2022
a575717
deleted pubspec.lock
Nov 28, 2022
8607808
pubspec.lock in gitignore
Nov 28, 2022
1bbc092
comment fixes (3)
Nov 28, 2022
65dc521
updating & blocking complete unit button (#23692)
Nov 28, 2022
d55622e
missing await
Nov 28, 2022
c6004b0
no final else
Nov 28, 2022
0a76b40
pubspec.lock ignored only in PGC
Nov 29, 2022
749d8b1
pubspec.lock
Nov 29, 2022
fb1fea1
comment fixes (4)
Nov 29, 2022
ef63740
rearranged completeUnit (#23692)
Nov 29, 2022
4b2d855
renamed user progress model to unit progress (#23692)
Nov 29, 2022
27b26e4
clearUpdatingUnitId (#23692)
Nov 29, 2022
b6c4e3e
added async (#23692)
Nov 29, 2022
1e38328
removed "fix exception" todo after filing an issue (#23692)
Nov 29, 2022
96e41f7
Merge from master
Nov 30, 2022
e215ec4
generated files
Nov 30, 2022
a107952
renamed user progress cache to unit progress (#23692)
Dec 1, 2022
8b639d0
all caches extend cache (#23692)
Dec 1, 2022
c8db1ef
refined open overlay (#23692)
Dec 1, 2022
869b40c
extracted overlay body (#23692)
Dec 1, 2022
9720c13
moved dismissible overlay (#23692)
Dec 1, 2022
9e1bbb0
specific imports (#23692)
Dec 1, 2022
af936d0
added firebase_options.dart into gradle rat exclusions & added a miss…
Dec 1, 2022
36d3105
hint in dialog (#24394)
Dec 1, 2022
338c673
extracted widgets, hints emptiness check (#24394)
Dec 2, 2022
48ea57d
title in unit content (#24394)
Dec 2, 2022
372b97f
group progress indicator size adjustment (#24394)
Dec 2, 2022
5e3ac58
renamed to unit content widget (#24394)
Dec 2, 2022
5ca4846
show solution snippets (#24394)
Dec 2, 2022
59d0fd3
solution managed inside of tour notifier (#24394)
Dec 2, 2022
63745d5
Merge branch 'issue23692_auth' into issue24538-tobf-save-user-code
Dec 6, 2022
e768604
updated import (#24538)
Dec 6, 2022
d442e63
no duplicate slash with reg exp (#24538)
Dec 7, 2022
44172c5
Merge branch 'issue24394-tobf-hint' into issue24538-tobf-save-user-code
Dec 8, 2022
90b9e3d
save user code barely works
Dec 8, 2022
8dd7098
user menu without padding
Dec 8, 2022
a850262
getUnitSnippets in unit progress (#24538)
Dec 27, 2022
8cd106d
Merge branch 'master' into issue24538-save-user-code
Jan 17, 2023
d3b0085
merge fixes (#24538)
Jan 17, 2023
eb23673
setSaveCodeListener to activeFileController.codeController (#24538)
Jan 20, 2023
b6cb6b9
Merge branch 'master' into issue24538-save-user-code
Jan 20, 2023
725e8d1
post-merge commit (#24538)
Jan 20, 2023
ece905c
pre-review fixes (#24538)
Jan 22, 2023
ebce111
set show solution false on reset (#24538)
Jan 22, 2023
92b4ec4
tested with show solution (#24538)
Jan 23, 2023
ea8acc0
removed comment after discussion (#24538)
Jan 23, 2023
18ecd23
reset is shown immediately (#24538)
Jan 23, 2023
a5310e0
missing notifyListeners (#24538)
Jan 23, 2023
f2d2f8f
reverted to unitProgress (#24538)
Jan 23, 2023
25dec32
comment fixes (#24538)
Jan 24, 2023
f3d1c0f
snippet type enum switcher (#24538)
Jan 26, 2023
d4401c9
comment fixes (#24538)
Jan 26, 2023
fff0bfa
save code status (#24538)
Jan 26, 2023
01611b0
comment fixes (#24538)
Feb 1, 2023
a836d01
comment fixes(#24538)
Feb 2, 2023
bfc7596
getUnitSavedSnippetId (#24538)
Feb 3, 2023
4e3d3cf
alphabetic order (#24538)
Feb 3, 2023
52227d5
deleted unitProgressByUnitId getter (#24538)
Feb 3, 2023
7f943d5
organized TourNotifier (#24538)
Feb 3, 2023
8eed5d3
comment fixes (#24538)
Feb 3, 2023
c7c51b1
commit to relaunch RAT check (#24538)
Feb 6, 2023
5637c41
scrollable hints (#24538)
Feb 6, 2023
4a419a6
moved hints to the left (#24538)
Feb 6, 2023
5381d9e
_Buttons padding (#24538)
Feb 6, 2023
9e3666c
set sdkId to fix a bug (#24538)
Feb 8, 2023
6860d1b
Flutter v3.7.3 support for ToB (#25283)
Feb 20, 2023
08989ab
Merge branch 'master' into issue24538-save-user-code
Feb 22, 2023
56264ac
flutter v3.7 support (#24538)
Feb 22, 2023
f755775
resolve deprecation warnings todo (#25283)
Feb 22, 2023
5d22b4c
scrollbar in markdown code block (#25529)
Feb 23, 2023
b638355
added missing notifyListeners (#24538)
Feb 23, 2023
1521ab9
CodeBlock widget (#25529)
Feb 23, 2023
bdf6f49
Merge branch 'issue24538-save-user-code' into issue25283-tobf-sucfuu
Feb 27, 2023
20e097e
deleted google_sign_in from pubspec (#25283)
Feb 27, 2023
6b54331
unfinished ContentExampleLoadingDescriptor (#25283)
Feb 28, 2023
8c7807b
setUnit & HiveLocalStorageCache (#25283)
Mar 2, 2023
879795b
Merge branch 'master' into issue24538-save-user-code
Mar 14, 2023
426d43e
untested multi-file saving (#25283)
Mar 15, 2023
099b0f1
changes for demo (#25283)
Mar 17, 2023
172f18f
comment fixes (#25283)
Mar 20, 2023
8575c6e
addressing comments (#25283)
Mar 24, 2023
7066061
Merge branch 'master' into issue24538-save-user-code
Mar 24, 2023
8410493
comments (#25283)
Mar 24, 2023
cc7ff54
Merge branch 'issue24538-save-user-code' into issue25283-tobf-sucfuu
Mar 24, 2023
b9d76e6
comments (#25283)
Mar 27, 2023
7dbb6b4
_getStandardOrEmptyDescriptor (#25283)
Mar 27, 2023
3434381
getSavedDescriptor (#25283)
Mar 27, 2023
be3e346
Improve comments, remove unused code (#25283)
alexeyinkin Mar 28, 2023
7b487a0
disabled saving solution code (#25283)
Mar 28, 2023
c796d85
_isSnippetTypeSavable (#25283)
Mar 28, 2023
95c82ec
Merge pull request #441 from akvelon/issue25283-tobf-sucfuu
nausharipov Mar 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion learning/tour-of-beam/frontend/assets/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ ui:
reportIssue: Report Issue in GitHub
signIn: Sign in
signOut: Sign out
solution: Solution
toWebsite: To Apache Beam website

pages:
Expand All @@ -38,7 +37,12 @@ pages:
startTour: Start your tour
title: Welcome to the Tour of Beam!
tour:
assignment: Assignment
completeUnit: Complete Unit
example: Example
myCode: My code
saving: Saving...
solution: Solution
summaryTitle: Table of Contents

dialogs:
Expand Down
9 changes: 6 additions & 3 deletions learning/tour-of-beam/frontend/lib/cache/unit_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ class UnitContentCache extends Cache {
final _unitContents = <String, Map<String, UnitContentModel>>{};
final _futures = <String, Map<String, Future<UnitContentModel>>>{};

UnitContentModel? getUnitContent(String sdkId, String unitId) {
Future<UnitContentModel> getUnitContent(
String sdkId,
String unitId,
) async {
final future = _futures[sdkId]?[unitId];
if (future == null) {
unawaited(_loadUnitContent(sdkId, unitId));
await _loadUnitContent(sdkId, unitId);
}

return _unitContents[sdkId]?[unitId];
return _unitContents[sdkId]![unitId]!;
}

Future<UnitContentModel> _loadUnitContent(String sdkId, String unitId) async {
Expand Down
136 changes: 104 additions & 32 deletions learning/tour-of-beam/frontend/lib/cache/unit_progress.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,92 @@

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:playground_components/playground_components.dart';

import '../auth/notifier.dart';
import '../enums/snippet_type.dart';
import '../enums/unit_completion.dart';
import '../models/unit_progress.dart';
import '../repositories/client/client.dart';
import '../repositories/models/get_user_progress_response.dart';
import '../repositories/user_progress/abstract.dart';
import '../repositories/user_progress/cloud.dart';
import '../repositories/user_progress/hive.dart';
import '../state.dart';
import 'cache.dart';

class UnitProgressCache extends Cache {
UnitProgressCache({required super.client});
class UnitProgressCache extends ChangeNotifier {
final _cloudUserProgressRepository = CloudUserProgressRepository(
client: GetIt.instance.get<TobClient>(),
);
final _localStorageUserProgressRepository = HiveUserProgressRepository();

AbstractUserProgressRepository _getUserProgressRepository() {
if (isAuthenticated) {
return _cloudUserProgressRepository;
}
return _localStorageUserProgressRepository;
}

Future<GetUserProgressResponse?>? _future;

var _unitProgress = <UnitProgressModel>[];
final _unitProgressByUnitId = <String, UnitProgressModel>{};

final _completedUnitIds = <String>{};
final _updatingUnitIds = <String>{};
Future<GetUserProgressResponse?>? _future;

bool get isAuthenticated =>
GetIt.instance.get<AuthNotifier>().isAuthenticated;

Future<void> loadUnitProgress(Sdk sdk) async {
_future = _getUserProgressRepository().getUserProgress(sdk);
final result = await _future;

_unitProgressByUnitId.clear();
if (result != null) {
_unitProgress = result.units;
for (final unitProgress in _unitProgress) {
_unitProgressByUnitId[unitProgress.id] = unitProgress;
}
} else {
_unitProgress = [];
}
notifyListeners();
}

List<UnitProgressModel> _getUnitProgress() {
if (_future == null) {
unawaited(loadUnitProgress(GetIt.instance.get<AppNotifier>().sdk!));
}
return _unitProgress;
}

// Completion

Future<void> completeUnit(String sdkId, String unitId) async {
try {
addUpdatingUnitId(unitId);
await _getUserProgressRepository().completeUnit(sdkId, unitId);
} finally {
await loadUnitProgress(GetIt.instance.get<AppNotifier>().sdk!);
clearUpdatingUnitId(unitId);
}
}

Set<String> getUpdatingUnitIds() => _updatingUnitIds;

Set<String> getCompletedUnits() {
_completedUnitIds.clear();
for (final unitProgress in _getUnitProgress()) {
if (unitProgress.isCompleted) {
_completedUnitIds.add(unitProgress.id);
}
}
return _completedUnitIds;
}

void addUpdatingUnitId(String unitId) {
_updatingUnitIds.add(unitId);
notifyListeners();
Expand All @@ -52,6 +121,14 @@ class UnitProgressCache extends Cache {
return _getUnitCompletion(unitId) == UnitCompletion.uncompleted;
}

bool isUnitCompleted(String? unitId) {
return getCompletedUnits().contains(unitId);
}

String? getUnitSavedSnippetId(String? unitId) {
return _unitProgressByUnitId[unitId]?.userSnippetId;
}

UnitCompletion _getUnitCompletion(String unitId) {
final authNotifier = GetIt.instance.get<AuthNotifier>();
if (!authNotifier.isAuthenticated) {
Expand All @@ -66,38 +143,33 @@ class UnitProgressCache extends Cache {
return UnitCompletion.uncompleted;
}

bool isUnitCompleted(String? unitId) {
return getCompletedUnits().contains(unitId);
}
// Snippet

Future<void> updateCompletedUnits() async {
final sdkId = GetIt.instance.get<AppNotifier>().sdkId;
if (sdkId != null) {
await _loadCompletedUnits(sdkId);
}
bool hasSavedSnippet(String? unitId) {
return _unitProgressByUnitId[unitId]?.userSnippetId != null;
}

Set<String> getCompletedUnits() {
if (_future == null) {
unawaited(updateCompletedUnits());
}

return _completedUnitIds;
Future<void> saveSnippet({
required Sdk sdk,
required List<SnippetFile> snippetFiles,
required SnippetType snippetType,
required String unitId,
}) async {
await _getUserProgressRepository().saveUnitSnippet(
sdk: sdk,
snippetFiles: snippetFiles,
snippetType: snippetType,
unitId: unitId,
);
}

Future<void> _loadCompletedUnits(String sdkId) async {
_future = client.getUserProgress(sdkId);
final result = await _future;

_completedUnitIds.clear();
if (result != null) {
for (final unitProgress in result.units) {
if (unitProgress.isCompleted) {
_completedUnitIds.add(unitProgress.id);
}
}
}

notifyListeners();
Future<ExampleLoadingDescriptor> getSavedDescriptor({
required Sdk sdk,
required String unitId,
}) async {
return _getUserProgressRepository().getSavedDescriptor(
sdk: sdk,
unitId: unitId,
);
}
}
10 changes: 4 additions & 6 deletions learning/tour-of-beam/frontend/lib/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,17 @@

// TODO(alexeyinkin): Generate this file on deployment.

const _cloudFunctionsProjectRegion = 'us-central1';
const _cloudFunctionsProjectId = 'tour-of-beam-2';
const _cloudFunctionsProjectRegion = 'us-east1';
const _cloudFunctionsProjectId = 'river-key-378010';
const cloudFunctionsBaseUrl = 'https://'
'$_cloudFunctionsProjectRegion-$_cloudFunctionsProjectId'
'.cloudfunctions.net';

// Copied from Playground's config.g.dart

const String kAnalyticsUA = 'UA-73650088-2';
const String kApiClientURL =
'https://backend-router-beta-dot-apache-beam-testing.appspot.com';
const String kApiJavaClientURL =
'https://backend-java-beta-dot-apache-beam-testing.appspot.com';
const String kApiClientURL = 'https://router.play-dev.beam.apache.org';
const String kApiJavaClientURL = 'https://java.play-dev.beam.apache.org';
const String kApiGoClientURL =
'https://backend-go-beta-dot-apache-beam-testing.appspot.com';
const String kApiPythonClientURL =
Expand Down
28 changes: 28 additions & 0 deletions learning/tour-of-beam/frontend/lib/constants/hive_box_names.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import 'package:playground_components/playground_components.dart';

class HiveBoxNames {
static const unitProgress = 'unit_progress';
static const snippets = 'snippets';

static String getSdkBoxName(Sdk sdk, String boxName) {
return '${sdk.id}_$boxName';
}
}
2 changes: 1 addition & 1 deletion learning/tour-of-beam/frontend/lib/constants/sizes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class TobSizes {
static const double footerHeight = 35;
static const double authOverlayWidth = 260;
static const double hintPopupWidth = 420;
static const double hintPopupWidth = 510;
}

class ScreenSizes {
Expand Down
23 changes: 23 additions & 0 deletions learning/tour-of-beam/frontend/lib/enums/save_code_status.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

enum SaveCodeStatus {
error,
saved,
saving,
}
23 changes: 23 additions & 0 deletions learning/tour-of-beam/frontend/lib/enums/snippet_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

enum SnippetType {
original,
saved,
solution,
}
12 changes: 6 additions & 6 deletions learning/tour-of-beam/frontend/lib/firebase_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ class DefaultFirebaseOptions {
}

static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyBtAreurqJ5D4IK6cNisZh5dnDRKljbJAw',
authDomain: 'astest-369409.firebaseapp.com',
projectId: 'astest-369409',
storageBucket: 'astest-369409.appspot.com',
messagingSenderId: '534850967604',
appId: '1:534850967604:web:55c6af8da7940df1ddd261',
apiKey: 'AIzaSyD-yN7OO9xjPQ5M-SJug96M2EfHwvjzd1A"',
authDomain: 'river-key-378010.firebaseapp.com"',
projectId: 'us-east1-river-key-378010',
storageBucket: 'river-key-378010.appspot.com',
messagingSenderId: '11155893632',
appId: '1:11155893632:web:0154abc4765db232086565',
);
}
2 changes: 1 addition & 1 deletion learning/tour-of-beam/frontend/lib/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void _initializeCaches() {
GetIt.instance.registerSingleton(ContentTreeCache(client: client));
GetIt.instance.registerSingleton(SdkCache(client: client));
GetIt.instance.registerSingleton(UnitContentCache(client: client));
GetIt.instance.registerSingleton(UnitProgressCache(client: client));
GetIt.instance.registerSingleton(UnitProgressCache());
}

void _initializeState() {
Expand Down
6 changes: 3 additions & 3 deletions learning/tour-of-beam/frontend/lib/models/unit_content.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion learning/tour-of-beam/frontend/lib/models/unit_progress.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@ import 'package:json_annotation/json_annotation.dart';

part 'unit_progress.g.dart';

@JsonSerializable(createToJson: false)
@JsonSerializable()
class UnitProgressModel {
final String id;
final bool isCompleted;
final String? userSnippetId;

const UnitProgressModel({
required this.id,
required this.isCompleted,
required this.userSnippetId,
});

factory UnitProgressModel.fromJson(Map<String, dynamic> json) =>
_$UnitProgressModelFromJson(json);

Map<String, dynamic> toJson() => _$UnitProgressModelToJson(this);
}
Loading