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

fix: missing build number ds-12 #13

Merged
merged 4 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 27 additions & 4 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ jobs:
- name: 📦 Get dependencies
run: flutter pub get

web-deploy:
web-github-pages:
name: 🚀 Web Deploy on Github Pages
needs: dependencies
runs-on: macos-latest

Expand All @@ -87,9 +88,20 @@ jobs:
dart run build_runner build -d
flutter gen-l10n

- name: 🏗️ Release build number setup
id: build-number
uses: onyxmueller/build-tag-number@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
prefix: build-number--web--github-action

- name: 🏗️ Build web release
env:
BASE_HREF: "/dicoding_story_fl/"
BUILD_NUMBER: ${{ steps.build-number.outputs.build_number }}
WEB_RENDERER: canvaskit
run: |
flutter build web --release --base-href "/dicoding_story_fl/" --web-renderer canvaskit
flutter build web --release --base-href ${{ env.BASE_HREF }} --build-number ${{ env.BUILD_NUMBER }} --build-number ${{ env.BUILD_NUMBER }} --web-renderer ${{ env.WEB_RENDERER }}

- name: 🚀 Deploy to Github Pages
uses: peaceiris/actions-gh-pages@v3
Expand All @@ -98,7 +110,8 @@ jobs:
publish_dir: ./build/web
publish_branch: web-release

gh-apk-release:
apk-github-release:
name: 🚀 Apk Release on Github Release
needs: dependencies
runs-on: macos-latest

Expand Down Expand Up @@ -126,8 +139,18 @@ jobs:
echo "${{ secrets.ANDROID_RELEASE_KEY_BASE64 }}" | base64 --decode > secrets/android-release-key.jks
echo "${{ secrets.ANDROID_KEY_PROPS_BASE64 }}" | base64 --decode > android/key.properties

- name: 🏗️ Release build number setup
id: build-number
uses: onyxmueller/build-tag-number@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
prefix: build-number--apk--github-release

- name: 🏗️ Build APK release
run: flutter build apk --release
env:
BUILD_NUMBER: ${{ steps.build-number.outputs.build_number }}
run: |
flutter build apk --release --build-number ${{ env.BUILD_NUMBER }}

- name: 📝 Release build
uses: ncipollo/release-action@v1
Expand Down
1 change: 1 addition & 0 deletions lib/domain/entities.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export "entities/app_exception_entity.dart";
export "entities/location_data_entity.dart";
export "entities/story_entity.dart";
export "entities/user_entity.dart";
42 changes: 42 additions & 0 deletions lib/domain/entities/location_data_entity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import "package:freezed_annotation/freezed_annotation.dart";

part "location_data_entity.freezed.dart";

@Freezed(copyWith: true)
class LocationData with _$LocationData {
const factory LocationData({
/// Stands for latitude.
required double lat,

/// Stands for longitude.
required double lon,
LocationPlaceData? placeData,
}) = _LocationData;

const LocationData._();

/// [lat], [lon] formatted as "lat, lon".
String get latLon => "$lat, $lon";

/// Get address from [placeData].
///
/// return [latLon] if address not found.
String get address => placeData?.address ?? latLon;

/// Get display name from [placeData].
///
/// return [address] if display name not found.
String get displayName => placeData?.displayName ?? address;
}

/// [g-maps-places-api]: https://developers.google.com/maps/documentation/places/web-service
///
/// [Google Maps Places API data][g-maps-places-api].
@Freezed(copyWith: true)
class LocationPlaceData with _$LocationPlaceData {
const factory LocationPlaceData({
required String id,
String? address,
String? displayName,
}) = _LocationPlaceData;
}
8 changes: 6 additions & 2 deletions lib/domain/entities/story_entity.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import "package:freezed_annotation/freezed_annotation.dart";
import "package:flutter/foundation.dart";
import "package:freezed_annotation/freezed_annotation.dart";

import "package:dicoding_story_fl/libs/decorators.dart";
import "location_data_entity.dart";

part "story_entity.freezed.dart";
part "story_entity.g.dart";

@freezed
@Freezed(copyWith: true)
class Story with _$Story {
const factory Story({
required String id,
Expand All @@ -16,6 +17,9 @@ class Story with _$Story {
@dateTimeJsonConverter required DateTime createdAt,
double? lat,
double? lon,

/// Detailed location data from reverse geocoding.
@ignoreJsonSerializable LocationData? location,
}) = _Story;

factory Story.fromJson(Map<String, Object?> json) => _$StoryFromJson(json);
Expand Down
10 changes: 6 additions & 4 deletions lib/interfaces/libs/widgets.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export "widgets/app_about_list_tile.dart";
export "widgets/common_network_image.dart";
export "widgets/custom_camera.dart";
export "widgets/email_text_field.dart";
export "widgets/image_from_x_file.dart";
export "widgets/list_tile/app_about_list_tile.dart";
export "widgets/list_tile/locale_list_tile.dart";
export "widgets/list_tile/theme_list_tile.dart";
export "widgets/media/common_network_image.dart";
export "widgets/media/custom_camera.dart";
export "widgets/media/image_from_x_file.dart";
export "widgets/password_text_field.dart";
export "widgets/sized_error_widget.dart";
export "widgets/story_card.dart";
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "package:dicoding_story_fl/libs/constants.dart";
class AppAboutListTile extends StatelessWidget {
const AppAboutListTile({super.key});

VoidCallback _onTapLink(BuildContext context, {required Uri url}) {
VoidCallback _handleUrlVisit(BuildContext context, {required Uri url}) {
return () async {
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
if (kIsWeb) return; // skip invalid error on web
Expand All @@ -21,8 +21,8 @@ class AppAboutListTile extends StatelessWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Hyperlink Fail"),
content: Text("Cannot launch $url"),
title: const Text("Url Visit Error"),
content: Text("Cannot visit $url"),
actions: [
TextButton(
onPressed: () => Navigator.maybePop(context),
Expand All @@ -48,7 +48,8 @@ class AppAboutListTile extends StatelessWidget {
image: AssetImages.appIconL,
width: 80.0,
),
applicationVersion: "v${package.version}+${package.buildNumber}",
applicationVersion: "v${package.version}"
"${package.buildNumber.isNotEmpty ? "+${package.buildNumber}" : ""}",
applicationLegalese: "MIT License\n\n"
"Copyright (c) 2024 Kemal Idris [KeidsID]",
aboutBoxChildren: [
Expand All @@ -65,7 +66,7 @@ class AppAboutListTile extends StatelessWidget {
text: "App Icon",
style: linkTextStyle,
recognizer: TapGestureRecognizer()
..onTap = _onTapLink(
..onTap = _handleUrlVisit(
context,
url: Uri.parse(
"https://www.flaticon.com/free-icon/content_15911316",
Expand All @@ -77,7 +78,7 @@ class AppAboutListTile extends StatelessWidget {
text: "Adrly",
style: linkTextStyle,
recognizer: TapGestureRecognizer()
..onTap = _onTapLink(
..onTap = _handleUrlVisit(
context,
url: Uri.parse(
"https://www.flaticon.com/authors/adrly",
Expand All @@ -89,7 +90,7 @@ class AppAboutListTile extends StatelessWidget {
text: "flaticon.com",
style: linkTextStyle,
recognizer: TapGestureRecognizer()
..onTap = _onTapLink(
..onTap = _handleUrlVisit(
context,
url: Uri.parse("https://www.flaticon.com/"),
),
Expand All @@ -103,7 +104,7 @@ class AppAboutListTile extends StatelessWidget {
Wrap(
children: [
TextButton(
onPressed: _onTapLink(
onPressed: _handleUrlVisit(
context,
url: Uri.parse("https://github.com/KeidsID/dicoding_story_fl"),
),
Expand Down
47 changes: 47 additions & 0 deletions lib/interfaces/libs/widgets/list_tile/locale_list_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import "package:flutter/material.dart";
import "package:provider/provider.dart";

import "package:dicoding_story_fl/interfaces/libs/l10n.dart";
import "package:dicoding_story_fl/interfaces/libs/providers.dart";

class LocaleListTile extends StatelessWidget {
const LocaleListTile({super.key});

@override
Widget build(BuildContext context) {
final appL10n = AppL10n.of(context)!;

return ListTile(
leading: const Icon(Icons.language_outlined),
title: Text(appL10n.language),
trailing: Builder(builder: (context) {
final localeProvider = context.watch<LocaleProvider>();

String localeString(String localeString) {
return switch (localeString) {
"en" => "English",
"id" => "Bahasa Indonesia",
_ => appL10n.flThemeMode(ThemeMode.system.name),
};
}

return DropdownButton<Locale?>(
value: localeProvider.value,
onChanged: (value) => localeProvider.value = value,
items: [
DropdownMenuItem(
value: null,
child: Text(localeString("system")),
),
...AppL10n.supportedLocales.map((e) {
return DropdownMenuItem(
value: e,
child: Text(localeString("$e")),
);
})
],
);
}),
);
}
}
47 changes: 47 additions & 0 deletions lib/interfaces/libs/widgets/list_tile/theme_list_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import "package:flutter/material.dart";
import "package:provider/provider.dart";

import "package:dicoding_story_fl/interfaces/libs/l10n.dart";
import "package:dicoding_story_fl/interfaces/libs/providers.dart";

class ThemeListTile extends StatelessWidget {
const ThemeListTile({super.key});

@override
Widget build(BuildContext context) {
final appL10n = AppL10n.of(context)!;

return ListTile(
leading: const Icon(Icons.color_lens_outlined),
title: Text(appL10n.appTheme),
trailing: Builder(builder: (context) {
final themeModeProvider = context.watch<ThemeModeProvider>();

final icons = ThemeMode.values.map((e) {
return switch (e) {
ThemeMode.system => Icons.settings_outlined,
ThemeMode.light => Icons.light_mode_outlined,
ThemeMode.dark => Icons.dark_mode_outlined,
};
}).toList();

return DropdownButton<ThemeMode>(
value: themeModeProvider.value,
items: ThemeMode.values.map((e) {
return DropdownMenuItem<ThemeMode>(
value: e,
child: Row(
children: [
Icon(icons[e.index]),
const SizedBox(width: 8.0),
Text(appL10n.flThemeMode(e.name)),
],
),
);
}).toList(),
onChanged: (value) => themeModeProvider.value = value!,
);
}),
);
}
}
Loading
Loading