~repos /only-bible-app

#kotlin#android#ios

git clone https://pyrossh.dev/repos/only-bible-app.git
Discussions: https://groups.google.com/g/rust-embed-devs

The only bible app you will ever need. No ads. No in-app purchases. No distractions.


adf4baee pyrossh

2 years ago
improve selector
bible_app/lib/components/book_selector.dart ADDED
@@ -0,0 +1,33 @@
1
+ import "package:flutter/material.dart";
2
+ import "package:flutter_reactive_value/flutter_reactive_value.dart";
3
+ import '../../../domain/book.dart';
4
+ import '../state.dart';
5
+ import 'books_list.dart';
6
+ import 'chapters_list.dart';
7
+
8
+ class BookSelector extends StatelessWidget {
9
+ const BookSelector({super.key});
10
+
11
+ @override
12
+ Widget build(BuildContext context) {
13
+ final tab = tabIndex.reactiveValue(context);
14
+ if (tab == 1) {
15
+ return Container(
16
+ margin: const EdgeInsets.only(top: 15, left: 20),
17
+ child: const ChaptersList(),
18
+ );
19
+ }
20
+ return Container(
21
+ margin: const EdgeInsets.only(top: 15, left: 20),
22
+ child: ListView(
23
+ children: [
24
+ BooksList(title: "Old Testament", offset: 0, books: oldTestament),
25
+ Container(
26
+ margin: const EdgeInsets.only(bottom: 10),
27
+ ),
28
+ BooksList(title: "New Testament", offset: 39, books: newTestament),
29
+ ],
30
+ ),
31
+ );
32
+ }
33
+ }
bible_app/lib/components/books_list.dart CHANGED
@@ -1,43 +1,44 @@
1
1
  import "package:flutter/material.dart";
2
+ import "package:kannada_bible_app/components/book_selector.dart";
3
+ import "package:kannada_bible_app/utils/string.dart";
2
4
  import "../state.dart";
5
+ import "title.dart";
3
6
 
4
7
  class BooksList extends StatelessWidget {
8
+ final String title;
5
9
  final int offset;
6
10
  final List<String> books;
7
11
 
8
- const BooksList({super.key, required this.offset, required this.books});
12
+ const BooksList({super.key, required this.title, required this.offset, required this.books});
9
13
 
10
14
  @override
11
15
  Widget build(BuildContext context) {
12
- return Wrap(
16
+ return Column(
13
- children: List.generate(books.length, (index) {
17
+ crossAxisAlignment: CrossAxisAlignment.start,
14
- final name = books[index].replaceAll(" ", "").substring(0, 3).toUpperCase();
15
- return InkWell(
16
- borderRadius: const BorderRadius.all(Radius.circular(30)),
17
- onTap: () {
18
+ children: [
18
- DefaultTabController.of(context).animateTo(1);
19
- tabBookIndex.value = offset + index;
20
- },
21
- child: Container(
19
+ Container(
22
- width: isDesktop() ? 90 : 50,
23
- height: isDesktop() ? 50 : 40,
24
- margin: const EdgeInsets.all(8),
20
+ margin: const EdgeInsets.only(bottom: 20),
21
+ child: Text(title, style: Theme
22
+ .of(context)
23
+ .textTheme
25
- child: Material(
24
+ .headlineMedium,
26
- elevation: 3,
27
- borderRadius: const BorderRadius.all(Radius.circular(30)),
28
- child: Center(
29
- child: Text(
30
- name,
31
- textAlign: TextAlign.center,
32
- style: Theme.of(context).textTheme.labelMedium,
33
- ),
34
- ),
35
- ),
36
25
  ),
26
+ ),
27
+ Wrap(
28
+ children: List.generate(books.length, (index) {
29
+ final name = books[index].bookShortName();
30
+ return InkWell(
31
+ borderRadius: const BorderRadius.all(Radius.circular(30)),
32
+ onTap: () {
33
+ // DefaultTabController.of(context).animateTo(1);
34
+ tabBookIndex.value = offset + index;
35
+ tabIndex.value = 1;
36
+ },
37
+ child: Tile(name: name),
37
- );
38
+ );
38
- }),
39
+ }),
40
+ ),
41
+ ],
39
42
  );
40
43
  }
41
44
  }
42
-
43
-
bible_app/lib/components/chapters_list.dart CHANGED
@@ -1,8 +1,11 @@
1
1
  import "package:flutter/material.dart";
2
+ import 'package:flutter/scheduler.dart';
2
3
  import 'package:flutter_reactive_value/flutter_reactive_value.dart';
4
+ import 'package:go_router/go_router.dart';
3
5
  import '../domain/kannada_gen.dart';
4
6
  import '../routes/index.dart';
5
7
  import '../state.dart';
8
+ import 'Title.dart';
6
9
 
7
10
  class ChaptersList extends StatelessWidget {
8
11
  const ChaptersList({super.key});
@@ -11,38 +14,29 @@ class ChaptersList extends StatelessWidget {
11
14
  Widget build(BuildContext context) {
12
15
  final bookIndex = tabBookIndex.reactiveValue(context);
13
16
  final book = kannadaBible[bookIndex];
14
- return ListView(children: [
17
+ return ListView(
18
+ children: [
15
- Container(
19
+ Container(
16
- margin: const EdgeInsets.only(bottom: 10, left: 10),
20
+ margin: const EdgeInsets.only(bottom: 20),
17
- child: Text(book.name, style: Theme.of(context).textTheme.headlineMedium),
21
+ child: Text(book.name, style: Theme.of(context).textTheme.headlineMedium),
18
- ),
22
+ ),
19
- Wrap(
23
+ Wrap(
20
- children: List.generate(book.chapters.length, (index) {
24
+ children: List.generate(book.chapters.length, (index) {
21
- return InkWell(
25
+ return InkWell(
22
- borderRadius: const BorderRadius.all(Radius.circular(30)),
26
+ borderRadius: const BorderRadius.all(Radius.circular(30)),
23
- onTap: () {
27
+ onTap: () {
24
- HomeScreenRoute(book: book.name, chapter: index).go(context);
28
+ HomeScreenRoute(book: book.name, chapter: index).go(context);
25
- saveState(bookIndex, index);
29
+ saveState(bookIndex, index);
30
+ context.pop();
31
+ SchedulerBinding.instance.addPostFrameCallback((_) {
32
+ tabIndex.value = 0;
33
+ });
26
- },
34
+ },
27
- child: Container(
28
- width: isDesktop() ? 90 : 50,
29
- height: isDesktop() ? 50 : 40,
30
- margin: const EdgeInsets.all(8),
31
- child: Material(
32
- elevation: 3,
33
- borderRadius: const BorderRadius.all(Radius.circular(30)),
34
- child: Center(
35
- child: Text(
36
- "${index + 1}",
35
+ child: Tile(name: "${index + 1}"),
37
- textAlign: TextAlign.center,
38
- style: Theme.of(context).textTheme.labelMedium,
39
- ),
40
- ),
41
- ),
42
- ),
43
- );
36
+ );
44
- }),
37
+ }),
45
- )
38
+ )
39
+ ],
46
- ]);
40
+ );
47
41
  }
48
- }
42
+ }
bible_app/lib/components/header.dart CHANGED
@@ -2,9 +2,11 @@ import "dart:math";
2
2
  import "package:flutter/material.dart";
3
3
  import "package:just_audio/just_audio.dart";
4
4
  import "package:kannada_bible_app/components/play_button.dart";
5
+ import "package:kannada_bible_app/components/slide_page.dart";
5
6
  import "package:kannada_bible_app/domain/book.dart";
6
7
  import "../routes/select.dart";
7
8
  import "../state.dart";
9
+ import "../utils/dialog.dart";
8
10
 
9
11
  class Header extends StatelessWidget {
10
12
  final int book;
@@ -29,7 +31,7 @@ class Header extends StatelessWidget {
29
31
  children: [
30
32
  InkWell(
31
33
  onTap: () {
32
- SelectScreenRoute().go(context);
34
+ Navigator.of(context).push(SlidePage());
33
35
  },
34
36
  child: Row(
35
37
  crossAxisAlignment: CrossAxisAlignment.center,
bible_app/lib/components/slide_page.dart ADDED
@@ -0,0 +1,56 @@
1
+ import "package:flutter/material.dart";
2
+ import "package:kannada_bible_app/components/book_selector.dart";
3
+
4
+ import "../state.dart";
5
+
6
+ class SlidePage extends ModalRoute<void> {
7
+ @override
8
+ Duration get transitionDuration => const Duration(milliseconds: 300);
9
+
10
+ @override
11
+ Duration get reverseTransitionDuration => const Duration(milliseconds: 300);
12
+
13
+ @override
14
+ bool get opaque => false;
15
+
16
+ @override
17
+ bool get barrierDismissible => true;
18
+
19
+ @override
20
+ Color get barrierColor => Colors.black.withOpacity(0.7);
21
+
22
+ @override
23
+ String? get barrierLabel => "Route";
24
+
25
+ @override
26
+ bool get maintainState => false;
27
+
28
+ @override
29
+ Widget buildPage(
30
+ BuildContext context,
31
+ Animation<double> animation,
32
+ Animation<double> secondaryAnimation,
33
+ ) {
34
+ return Material(
35
+ type: MaterialType.transparency,
36
+ child: Container(
37
+ color: Colors.white,
38
+ margin: EdgeInsets.only(left: 0, right: isDesktop() ? 650 : 0),
39
+ child: BookSelector(),
40
+ ),
41
+ );
42
+ }
43
+
44
+ @override
45
+ Widget buildTransitions(
46
+ BuildContext context,
47
+ Animation<double> animation,
48
+ Animation<double> secondaryAnimation,
49
+ Widget child,
50
+ ) {
51
+ return SlideTransition(
52
+ position: Tween(begin: const Offset(-1, 0), end: Offset.zero).animate(animation),
53
+ child: child,
54
+ );
55
+ }
56
+ }
bible_app/lib/components/title.dart ADDED
@@ -0,0 +1,51 @@
1
+ import 'package:flutter/material.dart';
2
+
3
+ import '../state.dart';
4
+
5
+ class Tile extends StatelessWidget {
6
+ final String name;
7
+
8
+ const Tile({super.key, required this.name});
9
+
10
+ @override
11
+ Widget build(BuildContext context) {
12
+ // Material(
13
+ // elevation: 3,
14
+ // borderRadius: const BorderRadius.all(Radius.circular(30)),
15
+ // child: Center(
16
+ // child: Text(
17
+ // name,
18
+ // textAlign: TextAlign.center,
19
+ // style: TextStyle(
20
+ // fontFamily: "SanFrancisco",
21
+ // fontSize: 20,
22
+ // fontWeight: FontWeight.w500,
23
+ // color: Color(0xFF9A1111),
24
+ // letterSpacing: 0.5,
25
+ // ),
26
+ // ),
27
+ // ),
28
+ // )
29
+ return Container(
30
+ width: isDesktop() ? 60 : 50,
31
+ height: isDesktop() ? 60 : 40,
32
+ margin: const EdgeInsets.only(right: 16, bottom: 16),
33
+ decoration: const BoxDecoration(
34
+ color: Color(0xFFEAE9E9),
35
+ ),
36
+ child: Center(
37
+ child: Text(
38
+ name,
39
+ textAlign: TextAlign.center,
40
+ style: const TextStyle(
41
+ fontFamily: "SanFrancisco",
42
+ fontSize: 20,
43
+ fontWeight: FontWeight.w500,
44
+ color: Color(0xFF9A1111),
45
+ letterSpacing: 0.5,
46
+ ),
47
+ ),
48
+ ),
49
+ );
50
+ }
51
+ }
bible_app/lib/domain/book.dart CHANGED
@@ -98,4 +98,4 @@ final newTestament = [
98
98
  "Revelation"
99
99
  ];
100
100
 
101
- final allBooks = oldTestament..addAll(newTestament);
101
+ final allBooks = List.from(oldTestament)..addAll(newTestament);
bible_app/lib/routes/index.dart CHANGED
@@ -26,7 +26,7 @@ class HomeScreenRoute extends GoRouteData {
26
26
  final selectedBook = kannadaBible.firstWhere((it) => book == it.name);
27
27
  final verses = selectedBook.chapters[chapter].verses;
28
28
 
29
- return NoPageTransition(
29
+ return NoTransitionPage(
30
30
  child: Column(
31
31
  children: [
32
32
  Header(book: allBooks.indexWhere((it) => it == book), chapter: chapter),
bible_app/lib/routes/select.dart CHANGED
@@ -19,86 +19,82 @@ class SelectScreenRoute extends GoRouteData {
19
19
  final width = MediaQuery.of(context).size.width;
20
20
  final right = isDesktop() ? width / 10 : 0.0;
21
21
  final left = isDesktop() ? 40.0 : 10.0;
22
- return NoPageTransition(
22
+ return NoTransitionPage(
23
+ child: Dialog(
24
+ backgroundColor: Colors.black.withOpacity(0.5),
25
+ elevation: 3,
23
- child: Column(
26
+ child: Column(
24
- crossAxisAlignment: CrossAxisAlignment.start,
27
+ crossAxisAlignment: CrossAxisAlignment.start,
25
- children: [
28
+ children: [
26
- Flexible(
29
+ Flexible(
27
- child: Container(
30
+ child: Container(
28
- margin: EdgeInsets.only(left: left, top: 20, right: right),
31
+ margin: EdgeInsets.only(left: left, top: 20, right: right),
29
- child: DefaultTabController(
32
+ child: DefaultTabController(
30
- length: 2,
33
+ length: 2,
31
- // animationDuration: Platform.isMacOS ? Duration.zero: const Duration(milliseconds: 300),
34
+ animationDuration: isDesktop() ? Duration.zero : const Duration(milliseconds: 300),
32
- child: Column(
35
+ child: Column(
33
- children: [
36
+ children: [
34
- SizedBox(
37
+ // SizedBox(
35
- width: 350,
38
+ // width: 350,
39
+ // child: TabBar(
40
+ // labelPadding: EdgeInsets.zero,
41
+ // labelColor: Colors.black,
42
+ // labelStyle: const TextStyle(
43
+ // fontSize: 14,
44
+ // fontWeight: FontWeight.w600,
45
+ // ),
46
+ // indicator: BoxDecoration(
47
+ // border: Border.all(color: Colors.blue.shade700, width: 3),
48
+ // borderRadius: BorderRadius.circular(50),
49
+ // ),
50
+ // tabs: const [
51
+ // Tab(
52
+ // child: Row(
53
+ // mainAxisSize: MainAxisSize.min,
54
+ // children: [
55
+ // Icon(Icons.book_outlined, color: Colors.red, size: 24),
56
+ // SizedBox(width: 8),
57
+ // Text('BOOK'),
58
+ // ],
59
+ // ),
60
+ // ),
61
+ // Tab(
62
+ // child: Row(
63
+ // mainAxisSize: MainAxisSize.min,
64
+ // children: [
65
+ // Icon(Icons.bookmark_outline, color: Colors.blue, size: 24),
66
+ // SizedBox(width: 8),
67
+ // Text('CHAPTER'),
68
+ // ],
69
+ // ),
70
+ // ),
71
+ // ],
72
+ // ),
73
+ // ),
74
+ // Container(
75
+ // margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
76
+ // decoration: const BoxDecoration(
77
+ // border: Border(bottom: BorderSide(width: 1.5)),
78
+ // ),
79
+ // ),
80
+ Expanded(
36
- child: TabBar(
81
+ child: TabBarView(
37
- labelPadding: EdgeInsets.zero,
38
- labelColor: Colors.black,
39
- labelStyle: const TextStyle(
40
- fontSize: 14,
82
+ children: [
83
+ ListView(children: [
84
+ BooksList(title: "Old Testament", offset: 0, books: oldTestament),
85
+ BooksList(title: "New Testament", offset: 39, books: newTestament),
86
+ ]),
41
- fontWeight: FontWeight.w600,
87
+ const ChaptersList(),
88
+ ],
42
89
  ),
43
- indicator: BoxDecoration(
44
- border: Border.all(color: Colors.blue.shade700, width: 3),
45
- borderRadius: BorderRadius.circular(50),
46
- ),
47
- tabs: const [
48
- Tab(
49
- child: Row(
50
- mainAxisSize: MainAxisSize.min,
51
- children: [
52
- Icon(Icons.book_outlined, color: Colors.red, size: 24),
53
- SizedBox(width: 8),
54
- Text('BOOK'),
55
- ],
56
- ),
57
- ),
58
- Tab(
59
- child: Row(
60
- mainAxisSize: MainAxisSize.min,
61
- children: [
62
- Icon(Icons.bookmark_outline, color: Colors.blue, size: 24),
63
- SizedBox(width: 8),
64
- Text('CHAPTER'),
65
- ],
66
- ),
67
- ),
68
- ],
69
- ),
70
- ),
71
- Container(
72
- margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
73
- decoration: const BoxDecoration(
74
- border: Border(bottom: BorderSide(width: 1.5)),
75
- ),
76
- ),
77
- Expanded(
78
- child: TabBarView(
79
- children: [
80
- ListView(children: [
81
- Container(
82
- margin: const EdgeInsets.only(bottom: 20, left: 10),
83
- child: Text("Old Testament", style: Theme.of(context).textTheme.headlineMedium),
84
- ),
85
- BooksList(offset: 0, books: oldTestament),
86
- Container(
87
- padding: const EdgeInsets.only(bottom: 20, top: 40, left: 10),
88
- child: Text("New Testament", style: Theme.of(context).textTheme.headlineMedium),
89
- ),
90
- BooksList(offset: 39, books: newTestament),
91
- ]),
92
- const ChaptersList(),
93
- ],
94
90
  ),
91
+ ],
95
- ),
92
+ ),
96
- ],
97
93
  ),
98
94
  ),
99
95
  ),
96
+ ],
100
- ),
97
+ ),
101
- ],
102
98
  ),
103
99
  );
104
100
  }
bible_app/lib/state.dart CHANGED
@@ -1,8 +1,12 @@
1
1
  import 'dart:io' show Platform;
2
2
  import 'package:flutter/material.dart';
3
+ import 'package:flutter/scheduler.dart';
3
4
  import 'package:flutter_reactive_value/flutter_reactive_value.dart';
5
+ import 'package:kannada_bible_app/utils/dialog.dart';
4
6
  import 'package:shared_preferences/shared_preferences.dart';
5
7
 
8
+ import 'components/book_selector.dart';
9
+
6
10
  final selectedVerses = ValueNotifier([]);
7
11
  final isPlaying = ValueNotifier(false);
8
12
 
@@ -26,10 +30,12 @@ onVerseSelected(int i) {
26
30
  }
27
31
  }
28
32
 
33
+ final tabIndex = ValueNotifier(0);
29
34
  final tabBookIndex = ValueNotifier(0);
30
35
 
31
36
  onTabBookChange(int i) {
32
37
  tabBookIndex.value = i;
38
+ tabIndex.value = 1;
33
39
  }
34
40
 
35
41
  Future<void> saveState(int bookIndex, int chapterIndex) async {
@@ -47,4 +53,19 @@ Future<(int, int)> loadState() async {
47
53
 
48
54
  bool isDesktop() {
49
55
  return Platform.isMacOS || Platform.isLinux || Platform.isWindows;
56
+ }
57
+
58
+
59
+ showBookMenu(BuildContext context) {
60
+ tabBookIndex.value = 0;
61
+ showCustomDialog<(int, int)>(context, BookSelector()).then((rec) {
62
+ if (rec != null) {
63
+ // selectedVerses.value.clear();
64
+ // onBookChange(rec.$1);
65
+ // onChapterChange(rec.$2);
66
+ SchedulerBinding.instance.addPostFrameCallback((duration) {
67
+ tabIndex.value = 0;
68
+ });
69
+ }
70
+ });
50
71
  }
bible_app/lib/utils/dialog.dart CHANGED
@@ -1,3 +1,4 @@
1
+ import "dart:ui";
1
2
  import "package:flutter/material.dart";
2
3
  import "package:go_router/go_router.dart";
3
4
 
@@ -30,19 +31,22 @@ showAlert(BuildContext context, String title, String message) {
30
31
  showDialog(
31
32
  context: context,
32
33
  builder: (_) {
34
+ return BackdropFilter(
35
+ filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
33
- return AlertDialog(
36
+ child: AlertDialog(
34
- title: Text(title),
37
+ title: Text(title),
35
- content: Text(message),
38
+ content: Text(message),
36
- actionsAlignment: MainAxisAlignment.center,
39
+ actionsAlignment: MainAxisAlignment.center,
37
- actionsOverflowButtonSpacing: 8.0,
40
+ actionsOverflowButtonSpacing: 8.0,
38
- actions: <Widget>[
41
+ actions: <Widget>[
39
- TextButton(
42
+ TextButton(
40
- child: const Text("Ok"),
43
+ child: const Text("Ok"),
41
- onPressed: () {
44
+ onPressed: () {
42
- context.pop();
45
+ context.pop();
43
- },
46
+ },
44
- ),
47
+ ),
45
- ],
48
+ ],
49
+ ),
46
50
  );
47
51
  },
48
52
  );
@@ -50,38 +54,4 @@ showAlert(BuildContext context, String title, String message) {
50
54
 
51
55
  showError(BuildContext context, String message) {
52
56
  showAlert(context, "Error", message);
53
- // return BackdropFilter(
54
- // filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
55
- // child: AlertDialog(
56
- // title: new Text(title,style: textStyle,),
57
- // content: new Text(content, style: textStyle,),
58
- // actions: <Widget>[
59
- // new FlatButton(
60
- // child: new Text("Continue"),
61
- // onPressed: () {
62
- // continueCallBack();
63
- // },
64
- // ),
65
- // new FlatButton(
66
- // child: Text("Cancel"),
67
- // onPressed: () {
68
- // Navigator.of(context).pop();
69
- // },
70
- // ),
71
- // ],
72
- // ));
73
- }
74
-
75
-
76
- class NoPageTransition extends CustomTransitionPage {
77
- NoPageTransition({required super.child})
78
- : super(
79
- transitionDuration: const Duration(milliseconds: 0),
80
- reverseTransitionDuration: const Duration(milliseconds: 0),
81
- transitionsBuilder: (context, animation, secondaryAnimation, child) {
82
- return FadeTransition(
83
- opacity: animation,
84
- child: child,
85
- );
86
- });
87
57
  }
bible_app/lib/utils/string.dart ADDED
@@ -0,0 +1,9 @@
1
+ extension StringExtension on String {
2
+ String bookShortName() {
3
+ // final name = replaceAll(" ", "").substring(0, 3);
4
+ if (this[0] == "1" || this[0] == "2" || this[0] == "3") {
5
+ return "${this[0]}${this[2].toUpperCase()}${substring(3, 4).toLowerCase()}";
6
+ }
7
+ return "${this[0].toUpperCase()}${substring(1, 3).toLowerCase()}";
8
+ }
9
+ }