Skip to content

Commit c78f0b6

Browse files
committed
Sync: 2024/12/02
2 parents fc8ff86 + b46087b commit c78f0b6

File tree

137 files changed

+5735
-1613
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+5735
-1613
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
3535
with:
3636
submodules: recursive
37-
- uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1
37+
- uses: subosito/flutter-action@74af56c5ed2697ba4621264652728e8d217e53d3
3838
with:
3939
channel: ${{ matrix.branch }}
4040
- name: Fetch Dart dependencies

.idx/dev.nix

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# To learn more about how to use Nix to configure your environment
2+
# see: https://developers.google.com/idx/guides/customize-idx-env
3+
{ pkgs, ... }: {
4+
# Which nixpkgs channel to use.
5+
channel = "stable-24.05"; # or "unstable"
6+
7+
# Use https://search.nixos.org/packages to find packages
8+
packages = [
9+
pkgs.nodejs_22
10+
pkgs.pnpm
11+
];
12+
13+
# Sets environment variables in the workspace
14+
env = {};
15+
idx = {
16+
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
17+
extensions = [
18+
"Dart-Code.flutter"
19+
"Dart-Code.dart-code"
20+
];
21+
22+
# Enable previews
23+
previews = {
24+
enable = true;
25+
previews = {
26+
web = {
27+
command = ["./dash_site" "serve"];
28+
manager = "web";
29+
env = {
30+
# Environment variables to set for your server
31+
PORT = "$PORT";
32+
};
33+
};
34+
};
35+
};
36+
37+
# Workspace lifecycle hooks
38+
workspace = {
39+
# Runs when a workspace is first created
40+
onCreate = {
41+
get-submodule = "git submodule update --init --recursive";
42+
pnpm-install = "pnpm install";
43+
};
44+
# Runs when the workspace is (re)started
45+
onStart = {
46+
# Example: start a background task to watch and re-build backend code
47+
# watch-backend = "npm run watch-backend";
48+
};
49+
};
50+
};
51+
}

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@ built with [Eleventy][] and hosted on [Firebase][].
1515
[Flutter]: https://docs.flutter.dev/
1616
[Repo on GitHub Actions]: https://github.com/flutter/website/actions?query=workflow%3Abuild+branch%3Amain
1717

18+
<a href="https://idx.google.com/import?url=https%3A%2F%2Fgithub.com%2Fflutter%2Fwebsite">
19+
<picture>
20+
<source
21+
media="(prefers-color-scheme: dark)"
22+
srcset="https://cdn.idx.dev/btn/open_dark_32.svg">
23+
<source
24+
media="(prefers-color-scheme: light)"
25+
srcset="https://cdn.idx.dev/btn/open_light_32.svg">
26+
<img
27+
height="32"
28+
alt="Open in IDX"
29+
src="https://cdn.idx.dev/btn/open_purple_32.svg">
30+
</picture>
31+
</a>
32+
1833
## Issues, bugs, and requests
1934

2035
We welcome contributions and feedback on our website.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Take our settings from the example_utils analysis_options.yaml file.
2+
# If necessary for a particular example, this file can also include
3+
# overrides for individual lints.
4+
5+
include: package:example_utils/analysis.yaml
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import 'dart:async';
2+
3+
import '../../domain/model/user_profile.dart';
4+
import '../services/api_client_service.dart';
5+
import '../services/database_service.dart';
6+
7+
class UserProfileRepository {
8+
UserProfileRepository({
9+
required ApiClientService apiClientService,
10+
required DatabaseService databaseService,
11+
}) : _apiClientService = apiClientService,
12+
_databaseService = databaseService {
13+
// #docregion Timer
14+
Timer.periodic(
15+
const Duration(minutes: 5),
16+
(timer) => sync(),
17+
);
18+
// #enddocregion Timer
19+
}
20+
21+
final ApiClientService _apiClientService;
22+
final DatabaseService _databaseService;
23+
24+
// #docregion getUserProfile
25+
Stream<UserProfile> getUserProfile() async* {
26+
// Fetch the user profile from the database
27+
final userProfile = await _databaseService.fetchUserProfile();
28+
// Returns the database result if it exists
29+
if (userProfile != null) {
30+
yield userProfile;
31+
}
32+
33+
// Fetch the user profile from the API
34+
try {
35+
final apiUserProfile = await _apiClientService.getUserProfile();
36+
//Update the database with the API result
37+
await _databaseService.updateUserProfile(apiUserProfile);
38+
// Return the API result
39+
yield apiUserProfile;
40+
} catch (e) {
41+
// Handle the error
42+
}
43+
}
44+
// #enddocregion getUserProfile
45+
46+
// #docregion getUserProfileFallback
47+
Future<UserProfile> getUserProfileFallback() async {
48+
try {
49+
// Fetch the user profile from the API
50+
final apiUserProfile = await _apiClientService.getUserProfile();
51+
//Update the database with the API result
52+
await _databaseService.updateUserProfile(apiUserProfile);
53+
54+
return apiUserProfile;
55+
} catch (e) {
56+
// If the network call failed,
57+
// fetch the user profile from the database
58+
final databaseUserProfile = await _databaseService.fetchUserProfile();
59+
60+
// If the user profile was never fetched from the API
61+
// it will be null, so throw an error
62+
if (databaseUserProfile != null) {
63+
return databaseUserProfile;
64+
} else {
65+
// Handle the error
66+
throw Exception('User profile not found');
67+
}
68+
}
69+
}
70+
// #enddocregion getUserProfileFallback
71+
72+
// #docregion getUserProfileLocal
73+
Future<UserProfile> getUserProfileLocal() async {
74+
// Fetch the user profile from the database
75+
final userProfile = await _databaseService.fetchUserProfile();
76+
77+
// Return the database result if it exists
78+
if (userProfile == null) {
79+
throw Exception('Data not found');
80+
}
81+
82+
return userProfile;
83+
}
84+
85+
Future<void> syncRead() async {
86+
try {
87+
// Fetch the user profile from the API
88+
final userProfile = await _apiClientService.getUserProfile();
89+
90+
// Update the database with the API result
91+
await _databaseService.updateUserProfile(userProfile);
92+
} catch (e) {
93+
// Try again later
94+
}
95+
}
96+
// #enddocregion getUserProfileLocal
97+
98+
// #docregion updateUserProfileOnline
99+
Future<void> updateUserProfileOnline(UserProfile userProfile) async {
100+
try {
101+
// Update the API with the user profile
102+
await _apiClientService.putUserProfile(userProfile);
103+
104+
// Only if the API call was successful
105+
// update the database with the user profile
106+
await _databaseService.updateUserProfile(userProfile);
107+
} catch (e) {
108+
// Handle the error
109+
}
110+
}
111+
// #enddocregion updateUserProfileOnline
112+
113+
// #docregion updateUserProfileOffline
114+
Future<void> updateUserProfileOffline(UserProfile userProfile) async {
115+
// Update the database with the user profile
116+
await _databaseService.updateUserProfile(userProfile);
117+
118+
try {
119+
// Update the API with the user profile
120+
await _apiClientService.putUserProfile(userProfile);
121+
} catch (e) {
122+
// Handle the error
123+
}
124+
}
125+
// #enddocregion updateUserProfileOffline
126+
127+
// #docregion sync
128+
Future<void> sync() async {
129+
try {
130+
// Fetch the user profile from the database
131+
final userProfile = await _databaseService.fetchUserProfile();
132+
133+
// Check if the user profile requires synchronization
134+
if (userProfile == null || userProfile.synchronized) {
135+
return;
136+
}
137+
138+
// Update the API with the user profile
139+
await _apiClientService.putUserProfile(userProfile);
140+
141+
// Set the user profile as synchronized
142+
await _databaseService
143+
.updateUserProfile(userProfile.copyWith(synchronized: true));
144+
} catch (e) {
145+
// Try again later
146+
}
147+
}
148+
// #enddocregion sync
149+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import '../../domain/model/user_profile.dart';
2+
3+
// #docregion ApiClientService
4+
class ApiClientService {
5+
/// performs GET network request to obtain a UserProfile
6+
Future<UserProfile> getUserProfile() async {
7+
// #enddocregion ApiClientService
8+
// Simulate a network GET request
9+
await Future.delayed(const Duration(seconds: 2));
10+
// Return a dummy user profile
11+
return const UserProfile(
12+
name: 'John Doe (from API)',
13+
photoUrl: 'https://example.com/john_doe.jpg',
14+
);
15+
// #docregion ApiClientService
16+
}
17+
18+
/// performs PUT network request to update a UserProfile
19+
Future<void> putUserProfile(UserProfile userProfile) async {
20+
// #enddocregion ApiClientService
21+
// Simulate a network PUT request
22+
await Future.delayed(const Duration(seconds: 2));
23+
// #docregion ApiClientService
24+
}
25+
}
26+
// #enddocregion ApiClientService
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import '../../domain/model/user_profile.dart';
2+
3+
// #docregion DatabaseService
4+
class DatabaseService {
5+
/// Fetches the UserProfile from the database.
6+
/// Returns null if the user profile is not found.
7+
Future<UserProfile?> fetchUserProfile() async {
8+
// #enddocregion DatabaseService
9+
// Simulate a database select query
10+
await Future.delayed(const Duration(milliseconds: 100));
11+
// Return a dummy user profile
12+
return const UserProfile(
13+
name: 'John Doe (from Database)',
14+
photoUrl: 'https://example.com/john_doe.jpg',
15+
);
16+
// #docregion DatabaseService
17+
}
18+
19+
/// Update UserProfile in the database.
20+
Future<void> updateUserProfile(UserProfile userProfile) async {
21+
// #enddocregion DatabaseService
22+
// Simulate a database update query
23+
await Future.delayed(const Duration(milliseconds: 100));
24+
// #docregion DatabaseService
25+
}
26+
}
27+
// #enddocregion DatabaseService
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'package:freezed_annotation/freezed_annotation.dart';
2+
3+
part 'user_profile.freezed.dart';
4+
5+
// #docregion UserProfile
6+
@freezed
7+
class UserProfile with _$UserProfile {
8+
const factory UserProfile({
9+
required String name,
10+
required String photoUrl,
11+
@Default(false) bool synchronized,
12+
}) = _UserProfile;
13+
}
14+
// #enddocregion UserProfile

0 commit comments

Comments
 (0)