Skip to content

Commit

Permalink
[sync] 2024/12/02 (cfug#1523)
Browse files Browse the repository at this point in the history
  • Loading branch information
AmosHuKe authored Dec 4, 2024
2 parents fc8ff86 + 1a9ee56 commit cfde1d4
Show file tree
Hide file tree
Showing 137 changed files with 5,750 additions and 1,613 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
submodules: recursive
- uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1
- uses: subosito/flutter-action@74af56c5ed2697ba4621264652728e8d217e53d3
with:
channel: ${{ matrix.branch }}
- name: Fetch Dart dependencies
Expand Down
51 changes: 51 additions & 0 deletions .idx/dev.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# To learn more about how to use Nix to configure your environment
# see: https://developers.google.com/idx/guides/customize-idx-env
{ pkgs, ... }: {
# Which nixpkgs channel to use.
channel = "stable-24.05"; # or "unstable"

# Use https://search.nixos.org/packages to find packages
packages = [
pkgs.nodejs_22
pkgs.pnpm
];

# Sets environment variables in the workspace
env = {};
idx = {
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
extensions = [
"Dart-Code.flutter"
"Dart-Code.dart-code"
];

# Enable previews
previews = {
enable = true;
previews = {
web = {
command = ["./dash_site" "serve"];
manager = "web";
env = {
# Environment variables to set for your server
PORT = "$PORT";
};
};
};
};

# Workspace lifecycle hooks
workspace = {
# Runs when a workspace is first created
onCreate = {
get-submodule = "git submodule update --init --recursive";
pnpm-install = "pnpm install";
};
# Runs when the workspace is (re)started
onStart = {
# Example: start a background task to watch and re-build backend code
# watch-backend = "npm run watch-backend";
};
};
};
}
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ built with [Eleventy][] and hosted on [Firebase][].
[Flutter]: https://docs.flutter.dev/
[Repo on GitHub Actions]: https://github.com/flutter/website/actions?query=workflow%3Abuild+branch%3Amain

<a href="https://idx.google.com/import?url=https%3A%2F%2Fgithub.com%2Fflutter%2Fwebsite">
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="https://cdn.idx.dev/btn/open_dark_32.svg">
<source
media="(prefers-color-scheme: light)"
srcset="https://cdn.idx.dev/btn/open_light_32.svg">
<img
height="32"
alt="Open in IDX"
src="https://cdn.idx.dev/btn/open_purple_32.svg">
</picture>
</a>

## Issues, bugs, and requests

We welcome contributions and feedback on our website.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Take our settings from the example_utils analysis_options.yaml file.
# If necessary for a particular example, this file can also include
# overrides for individual lints.

include: package:example_utils/analysis.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import 'dart:async';

import '../../domain/model/user_profile.dart';
import '../services/api_client_service.dart';
import '../services/database_service.dart';

class UserProfileRepository {
UserProfileRepository({
required ApiClientService apiClientService,
required DatabaseService databaseService,
}) : _apiClientService = apiClientService,
_databaseService = databaseService {
// #docregion Timer
Timer.periodic(
const Duration(minutes: 5),
(timer) => sync(),
);
// #enddocregion Timer
}

final ApiClientService _apiClientService;
final DatabaseService _databaseService;

// #docregion getUserProfile
Stream<UserProfile> getUserProfile() async* {
// Fetch the user profile from the database
final userProfile = await _databaseService.fetchUserProfile();
// Returns the database result if it exists
if (userProfile != null) {
yield userProfile;
}

// Fetch the user profile from the API
try {
final apiUserProfile = await _apiClientService.getUserProfile();
//Update the database with the API result
await _databaseService.updateUserProfile(apiUserProfile);
// Return the API result
yield apiUserProfile;
} catch (e) {
// Handle the error
}
}
// #enddocregion getUserProfile

// #docregion getUserProfileFallback
Future<UserProfile> getUserProfileFallback() async {
try {
// Fetch the user profile from the API
final apiUserProfile = await _apiClientService.getUserProfile();
//Update the database with the API result
await _databaseService.updateUserProfile(apiUserProfile);

return apiUserProfile;
} catch (e) {
// If the network call failed,
// fetch the user profile from the database
final databaseUserProfile = await _databaseService.fetchUserProfile();

// If the user profile was never fetched from the API
// it will be null, so throw an error
if (databaseUserProfile != null) {
return databaseUserProfile;
} else {
// Handle the error
throw Exception('User profile not found');
}
}
}
// #enddocregion getUserProfileFallback

// #docregion getUserProfileLocal
Future<UserProfile> getUserProfileLocal() async {
// Fetch the user profile from the database
final userProfile = await _databaseService.fetchUserProfile();

// Return the database result if it exists
if (userProfile == null) {
throw Exception('Data not found');
}

return userProfile;
}

Future<void> syncRead() async {
try {
// Fetch the user profile from the API
final userProfile = await _apiClientService.getUserProfile();

// Update the database with the API result
await _databaseService.updateUserProfile(userProfile);
} catch (e) {
// Try again later
}
}
// #enddocregion getUserProfileLocal

// #docregion updateUserProfileOnline
Future<void> updateUserProfileOnline(UserProfile userProfile) async {
try {
// Update the API with the user profile
await _apiClientService.putUserProfile(userProfile);

// Only if the API call was successful
// update the database with the user profile
await _databaseService.updateUserProfile(userProfile);
} catch (e) {
// Handle the error
}
}
// #enddocregion updateUserProfileOnline

// #docregion updateUserProfileOffline
Future<void> updateUserProfileOffline(UserProfile userProfile) async {
// Update the database with the user profile
await _databaseService.updateUserProfile(userProfile);

try {
// Update the API with the user profile
await _apiClientService.putUserProfile(userProfile);
} catch (e) {
// Handle the error
}
}
// #enddocregion updateUserProfileOffline

// #docregion sync
Future<void> sync() async {
try {
// Fetch the user profile from the database
final userProfile = await _databaseService.fetchUserProfile();

// Check if the user profile requires synchronization
if (userProfile == null || userProfile.synchronized) {
return;
}

// Update the API with the user profile
await _apiClientService.putUserProfile(userProfile);

// Set the user profile as synchronized
await _databaseService
.updateUserProfile(userProfile.copyWith(synchronized: true));
} catch (e) {
// Try again later
}
}
// #enddocregion sync
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import '../../domain/model/user_profile.dart';

// #docregion ApiClientService
class ApiClientService {
/// performs GET network request to obtain a UserProfile
Future<UserProfile> getUserProfile() async {
// #enddocregion ApiClientService
// Simulate a network GET request
await Future.delayed(const Duration(seconds: 2));
// Return a dummy user profile
return const UserProfile(
name: 'John Doe (from API)',
photoUrl: 'https://example.com/john_doe.jpg',
);
// #docregion ApiClientService
}

/// performs PUT network request to update a UserProfile
Future<void> putUserProfile(UserProfile userProfile) async {
// #enddocregion ApiClientService
// Simulate a network PUT request
await Future.delayed(const Duration(seconds: 2));
// #docregion ApiClientService
}
}
// #enddocregion ApiClientService
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import '../../domain/model/user_profile.dart';

// #docregion DatabaseService
class DatabaseService {
/// Fetches the UserProfile from the database.
/// Returns null if the user profile is not found.
Future<UserProfile?> fetchUserProfile() async {
// #enddocregion DatabaseService
// Simulate a database select query
await Future.delayed(const Duration(milliseconds: 100));
// Return a dummy user profile
return const UserProfile(
name: 'John Doe (from Database)',
photoUrl: 'https://example.com/john_doe.jpg',
);
// #docregion DatabaseService
}

/// Update UserProfile in the database.
Future<void> updateUserProfile(UserProfile userProfile) async {
// #enddocregion DatabaseService
// Simulate a database update query
await Future.delayed(const Duration(milliseconds: 100));
// #docregion DatabaseService
}
}
// #enddocregion DatabaseService
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'user_profile.freezed.dart';

// #docregion UserProfile
@freezed
class UserProfile with _$UserProfile {
const factory UserProfile({
required String name,
required String photoUrl,
@Default(false) bool synchronized,
}) = _UserProfile;
}
// #enddocregion UserProfile
Loading

0 comments on commit cfde1d4

Please sign in to comment.