mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 15:00:40 +00:00
ML-117 Improve description of paid features (#119)
* wip * added `LightmeterProSettingsSection` * hide Pro section on purchase * `ElevatedButton` -> `FilledButton` * moved Pro description to iap/README.md * intl * disable only list tiles * show iap dialog on every iap list tile
This commit is contained in:
parent
cc9f162933
commit
0fbf252d9e
11 changed files with 142 additions and 30 deletions
17
iap/README.md
Normal file
17
iap/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Lightmeter Pro
|
||||
|
||||
### Equipment profiles
|
||||
|
||||
Each equipment profile allows you to select:
|
||||
|
||||
- Aperture values and shutter speeds, that your lens and camera have
|
||||
- ND filters, that fit the chosen lens
|
||||
- ISO values, that your camera supports
|
||||
|
||||
Creating multiple profiles for different cameras and lenses allows you to easily switch between them and always have the relevant readings.
|
||||
|
||||
### Films in use
|
||||
|
||||
Select the films that you usually use. Selecting one will apply a correction to shutter speeds greater than 1" to compensate for the reciprocity failure.
|
||||
|
||||
Each equipment profile allows you to select:\n- Aperture values and shutter speeds, that your lens and camera have\n- ND filters, that fit the chosen lens\n- ISO values, that your camera supports\nCreating multiple profiles for different cameras and lenses allows you to easily switch between them and always have the relevant readings!
|
|
@ -92,5 +92,9 @@
|
|||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buyLightmeterPro": "Buy Lightmeter Pro",
|
||||
"lightmeterPro": "Lightmeter Pro",
|
||||
"lightmeterProDescription": "Unlocks extra features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.",
|
||||
"buy": "Buy"
|
||||
}
|
|
@ -92,5 +92,9 @@
|
|||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buyLightmeterPro": "Acheter Lightmeter Pro",
|
||||
"lightmeterPro": "Lightmeter Pro",
|
||||
"lightmeterProDescription": "Déverrouille des fonctionnalités supplémentaires, telles que des profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec une compensation pour ce que l'on appelle l'échec de réciprocité.\n\nLe code source du Lightmeter est disponible sur GitHub. Vous pouvez le compiler vous-même. Cependant, si vous souhaitez soutenir le développement et recevoir de nouvelles fonctionnalités et mises à jour, envisagez d'acheter Lightmeter Pro.",
|
||||
"buy": "Acheter"
|
||||
}
|
|
@ -92,5 +92,9 @@
|
|||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buyLightmeterPro": "Купить Lightmeter Pro",
|
||||
"lightmeterPro": "Lightmeter Pro",
|
||||
"lightmeterProDescription": "Даёт доступ к таким функциям как профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений, а также набору пленок с компенсацией эффекта Шварцшильда.\n\nИсходный код Lightmeter доступен на GitHub. Вы можете собрать его самостоятельно. Однако если вы хотите поддержать разработку и получать новые функции и обновления, то приобретите Lightmeter Pro.",
|
||||
"buy": "Купить"
|
||||
}
|
|
@ -92,5 +92,9 @@
|
|||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buyLightmeterPro": "Buy Lightmeter Pro",
|
||||
"lightmeterPro": "Lightmeter Pro",
|
||||
"lightmeterProDescription": "Unlocks extra features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.",
|
||||
"buy": "Buy"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart';
|
||||
import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart';
|
||||
|
||||
class BuyProListTile extends StatelessWidget {
|
||||
const BuyProListTile({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IAPListTile(
|
||||
leading: const Icon(Icons.star),
|
||||
title: Text(S.of(context).buyLightmeterPro),
|
||||
onTap: () {
|
||||
showBuyProDialog(context);
|
||||
},
|
||||
showPendingTrailing: true,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart';
|
||||
|
||||
class LightmeterProSettingsSection extends StatelessWidget {
|
||||
const LightmeterProSettingsSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SettingsSection(
|
||||
title: S.of(context).lightmeterPro,
|
||||
children: const [BuyProListTile()],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
/// Depends on the product status and replaces [onTap] with purchase callback
|
||||
|
@ -8,26 +10,37 @@ class IAPListTile extends StatelessWidget {
|
|||
final Icon leading;
|
||||
final Text title;
|
||||
final VoidCallback onTap;
|
||||
final bool showPendingTrailing;
|
||||
|
||||
const IAPListTile({
|
||||
this.product = IAPProductType.paidFeatures,
|
||||
required this.leading,
|
||||
required this.title,
|
||||
required this.onTap,
|
||||
this.showPendingTrailing = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final status = IAPProducts.productOf(context, IAPProductType.paidFeatures)?.status;
|
||||
final isPending = status == IAPProductStatus.purchased || status == null;
|
||||
return ListTile(
|
||||
leading: leading,
|
||||
title: title,
|
||||
onTap: switch (IAPProducts.productOf(context, product)?.status) {
|
||||
IAPProductStatus.purchasable => () => IAPProductsProvider.of(context).buy(product),
|
||||
onTap: switch (status) {
|
||||
IAPProductStatus.purchasable => () => showBuyProDialog(context),
|
||||
IAPProductStatus.pending => null,
|
||||
IAPProductStatus.purchased => onTap,
|
||||
null => null,
|
||||
},
|
||||
trailing: showPendingTrailing && isPending
|
||||
? const SizedBox(
|
||||
height: Dimens.grid24,
|
||||
width: Dimens.grid24,
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,10 @@ import 'package:lightmeter/res/dimens.dart';
|
|||
class SettingsSection extends StatelessWidget {
|
||||
final String title;
|
||||
final List<Widget> children;
|
||||
final bool enabled;
|
||||
|
||||
const SettingsSection({
|
||||
required this.title,
|
||||
required this.children,
|
||||
this.enabled = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
@ -25,25 +23,22 @@ class SettingsSection extends StatelessWidget {
|
|||
child: Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
||||
child: Opacity(
|
||||
opacity: enabled ? Dimens.enabledOpacity : Dimens.disabledOpacity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge
|
||||
?.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge
|
||||
?.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
...children,
|
||||
],
|
||||
),
|
||||
),
|
||||
...children,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
Future<void> showBuyProDialog(BuildContext context) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
icon: const Icon(Icons.star),
|
||||
titlePadding: Dimens.dialogIconTitlePadding,
|
||||
title: Text(S.of(context).lightmeterPro),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
|
||||
content: SingleChildScrollView(child: Text(S.of(context).lightmeterProDescription)),
|
||||
actionsPadding: Dimens.dialogActionsPadding,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
child: Text(S.of(context).cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
IAPProductsProvider.of(context).buy(IAPProductType.paidFeatures);
|
||||
},
|
||||
child: Text(S.of(context).buy),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
|
@ -3,10 +3,12 @@ import 'package:lightmeter/generated/l10n.dart';
|
|||
import 'package:lightmeter/screens/settings/components/about/widget_settings_section_about.dart';
|
||||
import 'package:lightmeter/screens/settings/components/equipment/widget_settings_section_equipment.dart';
|
||||
import 'package:lightmeter/screens/settings/components/general/widget_settings_section_general.dart';
|
||||
import 'package:lightmeter/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/metering/widget_settings_section_metering.dart';
|
||||
import 'package:lightmeter/screens/settings/components/theme/widget_settings_section_theme.dart';
|
||||
import 'package:lightmeter/screens/settings/flow_settings.dart';
|
||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class SettingsScreen extends StatefulWidget {
|
||||
const SettingsScreen({super.key});
|
||||
|
@ -43,6 +45,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||
SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
<Widget>[
|
||||
if (!IAPProducts.isPurchased(context, IAPProductType.paidFeatures))
|
||||
const LightmeterProSettingsSection(),
|
||||
const MeteringSettingsSection(),
|
||||
const EquipmentSettingsSection(),
|
||||
const GeneralSettingsSection(),
|
||||
|
|
Loading…
Reference in a new issue