├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── mzegar
│ │ │ │ └── flutterreddit
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── icon
│ └── rettericon.png
├── ios
├── .gitignore
├── Flutter
│ ├── .last_build_id
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-50x50@1x.png
│ │ ├── Icon-App-50x50@2x.png
│ │ ├── Icon-App-57x57@1x.png
│ │ ├── Icon-App-57x57@2x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-72x72@1x.png
│ │ ├── Icon-App-72x72@2x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── common
│ ├── config.dart
│ ├── launchURL.dart
│ ├── loadingPostIndicator.dart
│ ├── popupDialog.dart
│ ├── popupMenu.dart
│ ├── pullToRefresh.dart
│ ├── sortDialog.dart
│ └── subredditPost.dart
├── drawer.dart
├── main.dart
├── mainpage_viewmodel.dart
├── mainpage_viewmodel.g.dart
├── postpage.dart
├── postpage_viewmodel.dart
├── postpage_viewmodel.g.dart
├── profilepage.dart
├── profilepage_viewmodel.dart
└── profilepage_viewmodel.g.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshots
├── Video thumbnail.jpg
├── img1.png
├── img2.png
├── img3.jpg
├── img4.jpg
└── img5.jpg
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 | .vscode/*
23 | !.vscode/launch.json
24 |
25 | # Flutter/Dart/Pub related
26 | **/doc/api/
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Exceptions to above rules.
45 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
46 |
47 | # Repo specific
48 | *assets/config.json
49 | key.jks
50 | android/key.properties
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 1ad9baa8b99a2897c20f9e6e54d3b9b359ade314
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | # Retter
3 | [](https://github.com/mzegar/Retter/blob/master/LICENSE)
4 | [](https://github.com/mzegar/retter/stargazers)
5 |
6 |
7 | iOS/Android Reddit app created with Flutter
8 |
9 | https://play.google.com/store/apps/details?id=com.mzegar.flutterreddit
10 |
11 | ## Screenshots
12 |
13 |
14 |
15 | ## Building from source
16 |
17 | - Clone the repo, `cd Retter-master`
18 |
19 | - Run using `flutter run` or open with an IDE such as Android Studio
20 |
21 | ## Contribution
22 |
23 | I'm open to anyone contributing to this repo. I'd advise using Android Studio and running a `dartfmt` before creating a pull request: `dartfmt`.
24 | Pages are setup using [Mobx](https://pub.dev/packages/mobx) and a viewmodel pattern. Check out `src/main.dart` and `src/mainpage_viewmodel.dart`.
25 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | def keystoreProperties = new Properties()
29 | def keystorePropertiesFile = rootProject.file('key.properties')
30 | if (keystorePropertiesFile.exists()) {
31 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
32 | }
33 |
34 | android {
35 | compileSdkVersion 29
36 |
37 | sourceSets {
38 | main.java.srcDirs += 'src/main/kotlin'
39 | }
40 |
41 | lintOptions {
42 | disable 'InvalidPackage'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.mzegar.flutterreddit"
48 | minSdkVersion 16
49 | targetSdkVersion 29
50 | versionCode flutterVersionCode.toInteger()
51 | versionName flutterVersionName
52 | }
53 |
54 | signingConfigs {
55 | release {
56 | keyAlias keystoreProperties['keyAlias']
57 | keyPassword keystoreProperties['keyPassword']
58 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
59 | storePassword keystoreProperties['storePassword']
60 | }
61 | }
62 | buildTypes {
63 | release {
64 | signingConfig signingConfigs.release
65 | }
66 | }
67 | }
68 |
69 | flutter {
70 | source '../..'
71 | }
72 |
73 | dependencies {
74 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
75 | }
76 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
13 |
20 |
24 |
28 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
47 |
48 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/mzegar/flutterreddit/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mzegar.flutterreddit
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Flutter Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | include ':app'
6 |
7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
8 | def properties = new Properties()
9 |
10 | assert localPropertiesFile.exists()
11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
12 |
13 | def flutterSdkPath = properties.getProperty("flutter.sdk")
14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
16 |
17 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
18 |
19 | def plugins = new Properties()
20 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
21 | if (pluginsFile.exists()) {
22 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
23 | }
24 |
25 | plugins.each { name, path ->
26 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
27 | include ":$name"
28 | project(":$name").projectDir = pluginDirectory
29 | }
30 |
--------------------------------------------------------------------------------
/assets/icon/rettericon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/assets/icon/rettericon.png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/ios/Flutter/.last_build_id:
--------------------------------------------------------------------------------
1 | 93008d6801a698610bdd0b8d096e2756
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_web_browser (0.11.0):
4 | - Flutter
5 | - flutter_webview_plugin (0.0.1):
6 | - Flutter
7 | - path_provider (0.0.1):
8 | - Flutter
9 | - shared_preferences (0.0.1):
10 | - Flutter
11 | - url_launcher (0.0.1):
12 | - Flutter
13 |
14 | DEPENDENCIES:
15 | - Flutter (from `Flutter`)
16 | - flutter_web_browser (from `.symlinks/plugins/flutter_web_browser/ios`)
17 | - flutter_webview_plugin (from `.symlinks/plugins/flutter_webview_plugin/ios`)
18 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
19 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
20 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
21 |
22 | EXTERNAL SOURCES:
23 | Flutter:
24 | :path: Flutter
25 | flutter_web_browser:
26 | :path: ".symlinks/plugins/flutter_web_browser/ios"
27 | flutter_webview_plugin:
28 | :path: ".symlinks/plugins/flutter_webview_plugin/ios"
29 | path_provider:
30 | :path: ".symlinks/plugins/path_provider/ios"
31 | shared_preferences:
32 | :path: ".symlinks/plugins/shared_preferences/ios"
33 | url_launcher:
34 | :path: ".symlinks/plugins/url_launcher/ios"
35 |
36 | SPEC CHECKSUMS:
37 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
38 | flutter_web_browser: bdea232160dec44dec86540bee05168cc844ef7c
39 | flutter_webview_plugin: ed9e8a6a96baf0c867e90e1bce2673913eeac694
40 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
41 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
42 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
43 |
44 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
45 |
46 | COCOAPODS: 1.9.3
47 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 913C06D91504C3BA6831C6E3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C052FCD19AE175EF2B4F864C /* Pods_Runner.framework */; };
14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 2D4172F390F7599C96F6E11E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
37 | 639C6F6EE38420D28665F04C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
38 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
39 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
41 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
42 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
43 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
48 | C052FCD19AE175EF2B4F864C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
49 | FD591B746608904F1F7AD5EB /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | 913C06D91504C3BA6831C6E3 /* Pods_Runner.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 180D3D298C70E8ECD12DDD44 /* Pods */ = {
65 | isa = PBXGroup;
66 | children = (
67 | FD591B746608904F1F7AD5EB /* Pods-Runner.debug.xcconfig */,
68 | 2D4172F390F7599C96F6E11E /* Pods-Runner.release.xcconfig */,
69 | 639C6F6EE38420D28665F04C /* Pods-Runner.profile.xcconfig */,
70 | );
71 | name = Pods;
72 | path = Pods;
73 | sourceTree = "";
74 | };
75 | 24D9FF10E25E7D80CC413FCC /* Frameworks */ = {
76 | isa = PBXGroup;
77 | children = (
78 | C052FCD19AE175EF2B4F864C /* Pods_Runner.framework */,
79 | );
80 | name = Frameworks;
81 | sourceTree = "";
82 | };
83 | 9740EEB11CF90186004384FC /* Flutter */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
87 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
88 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
89 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
90 | );
91 | name = Flutter;
92 | sourceTree = "";
93 | };
94 | 97C146E51CF9000F007C117D = {
95 | isa = PBXGroup;
96 | children = (
97 | 9740EEB11CF90186004384FC /* Flutter */,
98 | 97C146F01CF9000F007C117D /* Runner */,
99 | 97C146EF1CF9000F007C117D /* Products */,
100 | 180D3D298C70E8ECD12DDD44 /* Pods */,
101 | 24D9FF10E25E7D80CC413FCC /* Frameworks */,
102 | );
103 | sourceTree = "";
104 | };
105 | 97C146EF1CF9000F007C117D /* Products */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 97C146EE1CF9000F007C117D /* Runner.app */,
109 | );
110 | name = Products;
111 | sourceTree = "";
112 | };
113 | 97C146F01CF9000F007C117D /* Runner */ = {
114 | isa = PBXGroup;
115 | children = (
116 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
117 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
118 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
119 | 97C147021CF9000F007C117D /* Info.plist */,
120 | 97C146F11CF9000F007C117D /* Supporting Files */,
121 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
122 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
123 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
124 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
125 | );
126 | path = Runner;
127 | sourceTree = "";
128 | };
129 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
130 | isa = PBXGroup;
131 | children = (
132 | );
133 | name = "Supporting Files";
134 | sourceTree = "";
135 | };
136 | /* End PBXGroup section */
137 |
138 | /* Begin PBXNativeTarget section */
139 | 97C146ED1CF9000F007C117D /* Runner */ = {
140 | isa = PBXNativeTarget;
141 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
142 | buildPhases = (
143 | C51104879926ABE595C7587B /* [CP] Check Pods Manifest.lock */,
144 | 9740EEB61CF901F6004384FC /* Run Script */,
145 | 97C146EA1CF9000F007C117D /* Sources */,
146 | 97C146EB1CF9000F007C117D /* Frameworks */,
147 | 97C146EC1CF9000F007C117D /* Resources */,
148 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
149 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
150 | B07AE4F81CB8AF789CFEC04E /* [CP] Embed Pods Frameworks */,
151 | );
152 | buildRules = (
153 | );
154 | dependencies = (
155 | );
156 | name = Runner;
157 | productName = Runner;
158 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
159 | productType = "com.apple.product-type.application";
160 | };
161 | /* End PBXNativeTarget section */
162 |
163 | /* Begin PBXProject section */
164 | 97C146E61CF9000F007C117D /* Project object */ = {
165 | isa = PBXProject;
166 | attributes = {
167 | LastUpgradeCheck = 1020;
168 | ORGANIZATIONNAME = "";
169 | TargetAttributes = {
170 | 97C146ED1CF9000F007C117D = {
171 | CreatedOnToolsVersion = 7.3.1;
172 | LastSwiftMigration = 1100;
173 | };
174 | };
175 | };
176 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
177 | compatibilityVersion = "Xcode 9.3";
178 | developmentRegion = en;
179 | hasScannedForEncodings = 0;
180 | knownRegions = (
181 | en,
182 | Base,
183 | );
184 | mainGroup = 97C146E51CF9000F007C117D;
185 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
186 | projectDirPath = "";
187 | projectRoot = "";
188 | targets = (
189 | 97C146ED1CF9000F007C117D /* Runner */,
190 | );
191 | };
192 | /* End PBXProject section */
193 |
194 | /* Begin PBXResourcesBuildPhase section */
195 | 97C146EC1CF9000F007C117D /* Resources */ = {
196 | isa = PBXResourcesBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
200 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
201 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
202 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
203 | );
204 | runOnlyForDeploymentPostprocessing = 0;
205 | };
206 | /* End PBXResourcesBuildPhase section */
207 |
208 | /* Begin PBXShellScriptBuildPhase section */
209 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
210 | isa = PBXShellScriptBuildPhase;
211 | buildActionMask = 2147483647;
212 | files = (
213 | );
214 | inputPaths = (
215 | );
216 | name = "Thin Binary";
217 | outputPaths = (
218 | );
219 | runOnlyForDeploymentPostprocessing = 0;
220 | shellPath = /bin/sh;
221 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
222 | };
223 | 9740EEB61CF901F6004384FC /* Run Script */ = {
224 | isa = PBXShellScriptBuildPhase;
225 | buildActionMask = 2147483647;
226 | files = (
227 | );
228 | inputPaths = (
229 | );
230 | name = "Run Script";
231 | outputPaths = (
232 | );
233 | runOnlyForDeploymentPostprocessing = 0;
234 | shellPath = /bin/sh;
235 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
236 | };
237 | B07AE4F81CB8AF789CFEC04E /* [CP] Embed Pods Frameworks */ = {
238 | isa = PBXShellScriptBuildPhase;
239 | buildActionMask = 2147483647;
240 | files = (
241 | );
242 | inputPaths = (
243 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
244 | "${PODS_ROOT}/../Flutter/Flutter.framework",
245 | "${BUILT_PRODUCTS_DIR}/flutter_web_browser/flutter_web_browser.framework",
246 | "${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework",
247 | "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
248 | "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
249 | "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
250 | );
251 | name = "[CP] Embed Pods Frameworks";
252 | outputPaths = (
253 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
254 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_web_browser.framework",
255 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_webview_plugin.framework",
256 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
257 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
258 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
259 | );
260 | runOnlyForDeploymentPostprocessing = 0;
261 | shellPath = /bin/sh;
262 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
263 | showEnvVarsInLog = 0;
264 | };
265 | C51104879926ABE595C7587B /* [CP] Check Pods Manifest.lock */ = {
266 | isa = PBXShellScriptBuildPhase;
267 | buildActionMask = 2147483647;
268 | files = (
269 | );
270 | inputFileListPaths = (
271 | );
272 | inputPaths = (
273 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
274 | "${PODS_ROOT}/Manifest.lock",
275 | );
276 | name = "[CP] Check Pods Manifest.lock";
277 | outputFileListPaths = (
278 | );
279 | outputPaths = (
280 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | shellPath = /bin/sh;
284 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
285 | showEnvVarsInLog = 0;
286 | };
287 | /* End PBXShellScriptBuildPhase section */
288 |
289 | /* Begin PBXSourcesBuildPhase section */
290 | 97C146EA1CF9000F007C117D /* Sources */ = {
291 | isa = PBXSourcesBuildPhase;
292 | buildActionMask = 2147483647;
293 | files = (
294 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
295 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
296 | );
297 | runOnlyForDeploymentPostprocessing = 0;
298 | };
299 | /* End PBXSourcesBuildPhase section */
300 |
301 | /* Begin PBXVariantGroup section */
302 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
303 | isa = PBXVariantGroup;
304 | children = (
305 | 97C146FB1CF9000F007C117D /* Base */,
306 | );
307 | name = Main.storyboard;
308 | sourceTree = "";
309 | };
310 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
311 | isa = PBXVariantGroup;
312 | children = (
313 | 97C147001CF9000F007C117D /* Base */,
314 | );
315 | name = LaunchScreen.storyboard;
316 | sourceTree = "";
317 | };
318 | /* End PBXVariantGroup section */
319 |
320 | /* Begin XCBuildConfiguration section */
321 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
322 | isa = XCBuildConfiguration;
323 | buildSettings = {
324 | ALWAYS_SEARCH_USER_PATHS = NO;
325 | CLANG_ANALYZER_NONNULL = YES;
326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
327 | CLANG_CXX_LIBRARY = "libc++";
328 | CLANG_ENABLE_MODULES = YES;
329 | CLANG_ENABLE_OBJC_ARC = YES;
330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
331 | CLANG_WARN_BOOL_CONVERSION = YES;
332 | CLANG_WARN_COMMA = YES;
333 | CLANG_WARN_CONSTANT_CONVERSION = YES;
334 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
336 | CLANG_WARN_EMPTY_BODY = YES;
337 | CLANG_WARN_ENUM_CONVERSION = YES;
338 | CLANG_WARN_INFINITE_RECURSION = YES;
339 | CLANG_WARN_INT_CONVERSION = YES;
340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
345 | CLANG_WARN_STRICT_PROTOTYPES = YES;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNREACHABLE_CODE = YES;
348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
350 | COPY_PHASE_STRIP = NO;
351 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
352 | ENABLE_NS_ASSERTIONS = NO;
353 | ENABLE_STRICT_OBJC_MSGSEND = YES;
354 | GCC_C_LANGUAGE_STANDARD = gnu99;
355 | GCC_NO_COMMON_BLOCKS = YES;
356 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
357 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
358 | GCC_WARN_UNDECLARED_SELECTOR = YES;
359 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
360 | GCC_WARN_UNUSED_FUNCTION = YES;
361 | GCC_WARN_UNUSED_VARIABLE = YES;
362 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
363 | MTL_ENABLE_DEBUG_INFO = NO;
364 | SDKROOT = iphoneos;
365 | SUPPORTED_PLATFORMS = iphoneos;
366 | TARGETED_DEVICE_FAMILY = "1,2";
367 | VALIDATE_PRODUCT = YES;
368 | };
369 | name = Profile;
370 | };
371 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
372 | isa = XCBuildConfiguration;
373 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
374 | buildSettings = {
375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
376 | CLANG_ENABLE_MODULES = YES;
377 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
378 | ENABLE_BITCODE = NO;
379 | FRAMEWORK_SEARCH_PATHS = (
380 | "$(inherited)",
381 | "$(PROJECT_DIR)/Flutter",
382 | );
383 | INFOPLIST_FILE = Runner/Info.plist;
384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
385 | LIBRARY_SEARCH_PATHS = (
386 | "$(inherited)",
387 | "$(PROJECT_DIR)/Flutter",
388 | );
389 | PRODUCT_BUNDLE_IDENTIFIER = com.mzegar.flutterreddit;
390 | PRODUCT_NAME = "$(TARGET_NAME)";
391 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
392 | SWIFT_VERSION = 5.0;
393 | VERSIONING_SYSTEM = "apple-generic";
394 | };
395 | name = Profile;
396 | };
397 | 97C147031CF9000F007C117D /* Debug */ = {
398 | isa = XCBuildConfiguration;
399 | buildSettings = {
400 | ALWAYS_SEARCH_USER_PATHS = NO;
401 | CLANG_ANALYZER_NONNULL = YES;
402 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
403 | CLANG_CXX_LIBRARY = "libc++";
404 | CLANG_ENABLE_MODULES = YES;
405 | CLANG_ENABLE_OBJC_ARC = YES;
406 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
407 | CLANG_WARN_BOOL_CONVERSION = YES;
408 | CLANG_WARN_COMMA = YES;
409 | CLANG_WARN_CONSTANT_CONVERSION = YES;
410 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
411 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
412 | CLANG_WARN_EMPTY_BODY = YES;
413 | CLANG_WARN_ENUM_CONVERSION = YES;
414 | CLANG_WARN_INFINITE_RECURSION = YES;
415 | CLANG_WARN_INT_CONVERSION = YES;
416 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
417 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
418 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
419 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
420 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
421 | CLANG_WARN_STRICT_PROTOTYPES = YES;
422 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
423 | CLANG_WARN_UNREACHABLE_CODE = YES;
424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
425 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
426 | COPY_PHASE_STRIP = NO;
427 | DEBUG_INFORMATION_FORMAT = dwarf;
428 | ENABLE_STRICT_OBJC_MSGSEND = YES;
429 | ENABLE_TESTABILITY = YES;
430 | GCC_C_LANGUAGE_STANDARD = gnu99;
431 | GCC_DYNAMIC_NO_PIC = NO;
432 | GCC_NO_COMMON_BLOCKS = YES;
433 | GCC_OPTIMIZATION_LEVEL = 0;
434 | GCC_PREPROCESSOR_DEFINITIONS = (
435 | "DEBUG=1",
436 | "$(inherited)",
437 | );
438 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
439 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
440 | GCC_WARN_UNDECLARED_SELECTOR = YES;
441 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
442 | GCC_WARN_UNUSED_FUNCTION = YES;
443 | GCC_WARN_UNUSED_VARIABLE = YES;
444 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
445 | MTL_ENABLE_DEBUG_INFO = YES;
446 | ONLY_ACTIVE_ARCH = YES;
447 | SDKROOT = iphoneos;
448 | TARGETED_DEVICE_FAMILY = "1,2";
449 | };
450 | name = Debug;
451 | };
452 | 97C147041CF9000F007C117D /* Release */ = {
453 | isa = XCBuildConfiguration;
454 | buildSettings = {
455 | ALWAYS_SEARCH_USER_PATHS = NO;
456 | CLANG_ANALYZER_NONNULL = YES;
457 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
458 | CLANG_CXX_LIBRARY = "libc++";
459 | CLANG_ENABLE_MODULES = YES;
460 | CLANG_ENABLE_OBJC_ARC = YES;
461 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
462 | CLANG_WARN_BOOL_CONVERSION = YES;
463 | CLANG_WARN_COMMA = YES;
464 | CLANG_WARN_CONSTANT_CONVERSION = YES;
465 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
467 | CLANG_WARN_EMPTY_BODY = YES;
468 | CLANG_WARN_ENUM_CONVERSION = YES;
469 | CLANG_WARN_INFINITE_RECURSION = YES;
470 | CLANG_WARN_INT_CONVERSION = YES;
471 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
472 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
473 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
475 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
476 | CLANG_WARN_STRICT_PROTOTYPES = YES;
477 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
478 | CLANG_WARN_UNREACHABLE_CODE = YES;
479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
481 | COPY_PHASE_STRIP = NO;
482 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
483 | ENABLE_NS_ASSERTIONS = NO;
484 | ENABLE_STRICT_OBJC_MSGSEND = YES;
485 | GCC_C_LANGUAGE_STANDARD = gnu99;
486 | GCC_NO_COMMON_BLOCKS = YES;
487 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
488 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
489 | GCC_WARN_UNDECLARED_SELECTOR = YES;
490 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
491 | GCC_WARN_UNUSED_FUNCTION = YES;
492 | GCC_WARN_UNUSED_VARIABLE = YES;
493 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
494 | MTL_ENABLE_DEBUG_INFO = NO;
495 | SDKROOT = iphoneos;
496 | SUPPORTED_PLATFORMS = iphoneos;
497 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
498 | TARGETED_DEVICE_FAMILY = "1,2";
499 | VALIDATE_PRODUCT = YES;
500 | };
501 | name = Release;
502 | };
503 | 97C147061CF9000F007C117D /* Debug */ = {
504 | isa = XCBuildConfiguration;
505 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
506 | buildSettings = {
507 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
508 | CLANG_ENABLE_MODULES = YES;
509 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
510 | ENABLE_BITCODE = NO;
511 | FRAMEWORK_SEARCH_PATHS = (
512 | "$(inherited)",
513 | "$(PROJECT_DIR)/Flutter",
514 | );
515 | INFOPLIST_FILE = Runner/Info.plist;
516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
517 | LIBRARY_SEARCH_PATHS = (
518 | "$(inherited)",
519 | "$(PROJECT_DIR)/Flutter",
520 | );
521 | PRODUCT_BUNDLE_IDENTIFIER = com.mzegar.flutterreddit;
522 | PRODUCT_NAME = "$(TARGET_NAME)";
523 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
524 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
525 | SWIFT_VERSION = 5.0;
526 | VERSIONING_SYSTEM = "apple-generic";
527 | };
528 | name = Debug;
529 | };
530 | 97C147071CF9000F007C117D /* Release */ = {
531 | isa = XCBuildConfiguration;
532 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
533 | buildSettings = {
534 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
535 | CLANG_ENABLE_MODULES = YES;
536 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
537 | ENABLE_BITCODE = NO;
538 | FRAMEWORK_SEARCH_PATHS = (
539 | "$(inherited)",
540 | "$(PROJECT_DIR)/Flutter",
541 | );
542 | INFOPLIST_FILE = Runner/Info.plist;
543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
544 | LIBRARY_SEARCH_PATHS = (
545 | "$(inherited)",
546 | "$(PROJECT_DIR)/Flutter",
547 | );
548 | PRODUCT_BUNDLE_IDENTIFIER = com.mzegar.flutterreddit;
549 | PRODUCT_NAME = "$(TARGET_NAME)";
550 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
551 | SWIFT_VERSION = 5.0;
552 | VERSIONING_SYSTEM = "apple-generic";
553 | };
554 | name = Release;
555 | };
556 | /* End XCBuildConfiguration section */
557 |
558 | /* Begin XCConfigurationList section */
559 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
560 | isa = XCConfigurationList;
561 | buildConfigurations = (
562 | 97C147031CF9000F007C117D /* Debug */,
563 | 97C147041CF9000F007C117D /* Release */,
564 | 249021D3217E4FDB00AE95B9 /* Profile */,
565 | );
566 | defaultConfigurationIsVisible = 0;
567 | defaultConfigurationName = Release;
568 | };
569 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
570 | isa = XCConfigurationList;
571 | buildConfigurations = (
572 | 97C147061CF9000F007C117D /* Debug */,
573 | 97C147071CF9000F007C117D /* Release */,
574 | 249021D4217E4FDB00AE95B9 /* Profile */,
575 | );
576 | defaultConfigurationIsVisible = 0;
577 | defaultConfigurationName = Release;
578 | };
579 | /* End XCConfigurationList section */
580 | };
581 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
582 | }
583 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | Retter
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/common/config.dart:
--------------------------------------------------------------------------------
1 | import 'package:draw/draw.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 | import 'dart:async';
4 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
5 | import 'package:uuid/uuid.dart';
6 |
7 | class Config {
8 | // API Config
9 | static final String clientId = '9h-Tx1lSokXDPA';
10 | static final String userAgent = 'RetterApp';
11 | static final String redirectUri = 'https://mzegar.github.io/';
12 |
13 | static final String subredditKey = 'subreddits';
14 | static final String credentialsKey = 'credentials';
15 | final bool isAndroid;
16 | final SharedPreferences sharedPreferences;
17 |
18 | Config({
19 | this.isAndroid,
20 | this.sharedPreferences,
21 | }) {
22 | _init();
23 | }
24 |
25 | void _init() {
26 | if (!sharedPreferences.containsKey(subredditKey)) {
27 | sharedPreferences.setStringList(subredditKey, []);
28 | }
29 | }
30 |
31 | List saveSubreddit(String subreddit) {
32 | var sharedPreferencesSubs = sharedPreferences.getStringList(subredditKey);
33 | bool isSaved = false;
34 | sharedPreferencesSubs.forEach((val) {
35 | if (val.toLowerCase() == subreddit.toLowerCase()) {
36 | isSaved = true;
37 | }
38 | });
39 | if (!isSaved) {
40 | sharedPreferencesSubs.add(subreddit);
41 | sharedPreferences.setStringList(subredditKey, sharedPreferencesSubs);
42 | }
43 | return sharedPreferencesSubs;
44 | }
45 |
46 | List deleteSubreddit(String subreddit) {
47 | var sharedPreferencesSubs = sharedPreferences.getStringList(subredditKey);
48 | if (sharedPreferencesSubs.contains(subreddit)) {
49 | sharedPreferencesSubs.remove(subreddit);
50 | sharedPreferences.setStringList(subredditKey, sharedPreferencesSubs);
51 | }
52 | return sharedPreferencesSubs;
53 | }
54 |
55 | Future login(void Function(Reddit redditResponse) onLogin) async {
56 | FlutterWebviewPlugin flutterWebView = FlutterWebviewPlugin();
57 | final redditLogin = Reddit.createInstalledFlowInstance(
58 | clientId: clientId,
59 | userAgent: userAgent,
60 | redirectUri: Uri.parse(redirectUri),
61 | );
62 |
63 | final authUrl = redditLogin.auth.url(
64 | ['*'],
65 | userAgent,
66 | compactLogin: true,
67 | );
68 |
69 | flutterWebView.onUrlChanged.listen((String url) async {
70 | if (url.contains('$redirectUri?state=$userAgent&code=')) {
71 | var authCode = Uri.parse(url).queryParameters['code'];
72 | await redditLogin.auth.authorize(authCode);
73 | saveLoginDetails(redditLogin.auth.credentials.toJson());
74 | flutterWebView.close();
75 | onLogin(redditLogin);
76 | } else if (url
77 | .contains('$redirectUri?state=$userAgent&error=access_denied')) {
78 | // TODO: Failed to authenticate
79 | flutterWebView.close();
80 | onLogin(null);
81 | }
82 | });
83 |
84 | await flutterWebView.launch(authUrl.toString());
85 | }
86 |
87 | Future logout(void Function(Reddit redditResponse) onLogin) async {
88 | onLogin(await anonymousLogin());
89 | }
90 |
91 | void deleteLoginDetails() {
92 | sharedPreferences.setString(credentialsKey, '');
93 | }
94 |
95 | void saveLoginDetails(String jsonCredentials) {
96 | sharedPreferences.setString(credentialsKey, jsonCredentials);
97 | }
98 |
99 | String getLoginDetails() {
100 | return sharedPreferences.getString(credentialsKey);
101 | }
102 |
103 | Future onAppOpenLogin() async {
104 | var savedLoginCredentials = getLoginDetails();
105 | if (savedLoginCredentials == null || savedLoginCredentials.isEmpty) {
106 | return anonymousLogin();
107 | } else {
108 | Reddit client = Reddit.restoreInstalledAuthenticatedInstance(
109 | savedLoginCredentials,
110 | clientId: clientId,
111 | userAgent: userAgent,
112 | redirectUri: Uri.parse(redirectUri),
113 | );
114 |
115 | return client;
116 | }
117 | }
118 |
119 | Future anonymousLogin() async {
120 | final redditLogin = await Reddit.createUntrustedReadOnlyInstance(
121 | clientId: clientId,
122 | userAgent: userAgent,
123 | deviceId: Uuid().v1(),
124 | );
125 |
126 | return redditLogin;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/lib/common/launchURL.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_web_browser/flutter_web_browser.dart';
3 |
4 | Future launchURL(String url) async {
5 | FlutterWebBrowser.openWebPage(
6 | url: url,
7 | androidToolbarColor: Color(
8 | 0xFF030303,
9 | ),
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/lib/common/loadingPostIndicator.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 |
4 | Widget buildLoadingPostIndicator(String text) {
5 | return Padding(
6 | padding: EdgeInsets.all(10),
7 | child: Row(
8 | mainAxisAlignment: MainAxisAlignment.center,
9 | children: [
10 | Text(
11 | text,
12 | style: GoogleFonts.inter(),
13 | ),
14 | SizedBox(
15 | width: 10,
16 | ),
17 | Container(
18 | width: 20,
19 | height: 20,
20 | child: CircularProgressIndicator(),
21 | ),
22 | ],
23 | ),
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/common/popupDialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:google_fonts/google_fonts.dart';
4 |
5 | class PopupDialog extends StatelessWidget {
6 | final String dialogMessage;
7 |
8 | const PopupDialog({
9 | Key key,
10 | this.dialogMessage,
11 | }) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Column(
16 | mainAxisAlignment: MainAxisAlignment.end,
17 | children: [
18 | AlertDialog(
19 | backgroundColor: Color(0xFF121212),
20 | content: Text(
21 | dialogMessage,
22 | textAlign: TextAlign.center,
23 | style: GoogleFonts.inter(),
24 | ),
25 | ),
26 | ],
27 | );
28 | }
29 | }
30 |
31 | Future showPopupDialog({
32 | BuildContext context,
33 | String dialogMessage,
34 | }) async {
35 | return await showDialog(
36 | context: context,
37 | barrierColor: Colors.white.withOpacity(0),
38 | barrierDismissible: false,
39 | builder: (_) {
40 | Future.delayed(
41 | Duration(milliseconds: 750),
42 | () {
43 | Navigator.of(context).pop();
44 | },
45 | );
46 | return PopupDialog(
47 | dialogMessage: dialogMessage,
48 | );
49 | });
50 | }
51 |
--------------------------------------------------------------------------------
/lib/common/popupMenu.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 |
4 | enum popupMenuOptions { Login, Logout }
5 |
6 | class CustomPopupMenu extends StatelessWidget {
7 | final void Function(popupMenuOptions optionSelected) onTap;
8 | final bool isLoggedIn;
9 | final List _options = [];
10 |
11 | CustomPopupMenu({
12 | this.onTap,
13 | this.isLoggedIn,
14 | }) {
15 | isLoggedIn
16 | ? _options.add(popupMenuOptions.Logout)
17 | : _options.add(popupMenuOptions.Login);
18 | }
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return PopupMenuButton(
23 | color: Color(0xFF121212),
24 | itemBuilder: (BuildContext context) {
25 | return _options.map((option) {
26 | return PopupMenuItem(
27 | value: option,
28 | child: Padding(
29 | padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
30 | child: Text(
31 | option.toString().split('.').last,
32 | style: GoogleFonts.inter(),
33 | ),
34 | ),
35 | );
36 | }).toList();
37 | },
38 | onSelected: (popupMenuOptions option) {
39 | onTap(option);
40 | },
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/common/pullToRefresh.dart:
--------------------------------------------------------------------------------
1 | import 'package:eva_icons_flutter/eva_icons_flutter.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/cupertino.dart';
4 |
5 | Widget buildPullToRefresh(
6 | BuildContext context,
7 | RefreshIndicatorMode refreshState,
8 | double pulledExtent,
9 | double refreshTriggerPullDistance,
10 | double refreshIndicatorExtent,
11 | ) {
12 | if (pulledExtent < 15) {
13 | return Container();
14 | }
15 | switch (refreshState) {
16 | case RefreshIndicatorMode.inactive:
17 | case RefreshIndicatorMode.done:
18 | case RefreshIndicatorMode.armed:
19 | case RefreshIndicatorMode.refresh:
20 | return Container();
21 | break;
22 | case RefreshIndicatorMode.drag:
23 | return Center(
24 | child: Transform.rotate(
25 | angle: pulledExtent / 10,
26 | child: Container(
27 | width: 45,
28 | height: 45,
29 | child: Icon(
30 | EvaIcons.refresh,
31 | size: 17,
32 | ),
33 | decoration: BoxDecoration(
34 | shape: BoxShape.circle,
35 | color: Color(0xFF282828),
36 | ),
37 | ),
38 | ),
39 | );
40 | break;
41 | }
42 |
43 | return Container();
44 | }
45 |
--------------------------------------------------------------------------------
/lib/common/sortDialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class SortDialog extends StatelessWidget {
5 | final Widget content;
6 |
7 | SortDialog({
8 | @required this.content,
9 | });
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return CupertinoAlertDialog(content: content);
14 | }
15 | }
16 |
17 | Future showSortDialog({
18 | @required BuildContext context,
19 | @required Widget content,
20 | }) async {
21 | return await showDialog(
22 | context: context,
23 | builder: (_) {
24 | return SortDialog(
25 | content: content,
26 | );
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/lib/common/subredditPost.dart:
--------------------------------------------------------------------------------
1 | import 'package:draw/draw.dart';
2 | import 'package:eva_icons_flutter/eva_icons_flutter.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 | import 'package:flutter_markdown/flutter_markdown.dart';
6 | import 'package:flutterreddit/common/launchURL.dart';
7 | import 'package:flutterreddit/common/popupDialog.dart';
8 | import 'package:google_fonts/google_fonts.dart';
9 | import 'package:intl/intl.dart';
10 | import 'package:transparent_image/transparent_image.dart';
11 | import 'package:markdown/markdown.dart' as md;
12 |
13 | class SubredditPost extends StatefulWidget {
14 | final BuildContext context;
15 | final Submission submissionData;
16 | final bool isViewingPost;
17 | final bool isLoggedIn;
18 | final void Function() onTap;
19 | final void Function() onCommentTap;
20 | final void Function(String subreddit) onSubredditTap;
21 | final void Function(String name) onProfileTap;
22 | final String selfText;
23 |
24 | const SubredditPost({
25 | this.context,
26 | this.submissionData,
27 | this.isViewingPost,
28 | this.isLoggedIn,
29 | this.onTap,
30 | this.onCommentTap,
31 | this.onSubredditTap,
32 | this.onProfileTap,
33 | this.selfText,
34 | });
35 | @override
36 | _SubredditPostState createState() => _SubredditPostState();
37 | }
38 |
39 | class _SubredditPostState extends State {
40 | VoteState voteStatus = VoteState.none;
41 |
42 | @override
43 | void initState() {
44 | super.initState();
45 | }
46 |
47 | @override
48 | Widget build(BuildContext context) {
49 | var screenWidth = MediaQuery.of(context).size.width;
50 | return Padding(
51 | padding: EdgeInsets.symmetric(vertical: 5),
52 | child: Card(
53 | margin: EdgeInsets.zero,
54 | color: Color(0xFF282828),
55 | child: InkWell(
56 | onTap: () {
57 | if (widget.onTap != null) widget.onTap();
58 | },
59 | child: Column(
60 | children: [
61 | Column(
62 | crossAxisAlignment: CrossAxisAlignment.start,
63 | children: [
64 | Padding(
65 | padding: EdgeInsets.all(10),
66 | child: Column(
67 | crossAxisAlignment: CrossAxisAlignment.start,
68 | children: [
69 | Text(
70 | widget.submissionData.title,
71 | style: GoogleFonts.inter(
72 | fontWeight: FontWeight.w400,
73 | ),
74 | ),
75 | SizedBox(height: 4),
76 | InkWell(
77 | onTap: () {
78 | if (widget.onProfileTap != null)
79 | widget.onProfileTap(widget.submissionData.author);
80 | },
81 | child: Text(
82 | 'u/${widget.submissionData.author}',
83 | style: GoogleFonts.inter(
84 | color: Colors.blueGrey,
85 | fontSize: 11,
86 | decoration: TextDecoration.underline,
87 | ),
88 | ),
89 | ),
90 | SizedBox(height: 4),
91 | Row(
92 | children: [
93 | Text(
94 | '${NumberFormat.compact().format(widget.submissionData.upvotes + (voteStatus == VoteState.upvoted ? 1 : 0) + (voteStatus == VoteState.downvoted ? -1 : 0))} upvotes • ${widget.submissionData.numComments.toString()} comments • ',
95 | style: GoogleFonts.inter(
96 | color: Colors.white60,
97 | fontSize: 11,
98 | ),
99 | ),
100 | InkWell(
101 | onTap: () {
102 | if (widget.isViewingPost) {
103 | Navigator.pop(context);
104 | }
105 | widget.onSubredditTap(
106 | widget.submissionData.subreddit.displayName,
107 | );
108 | },
109 | child: Text(
110 | 'r/${widget.submissionData.subreddit.displayName}',
111 | style: GoogleFonts.inter(
112 | color: Colors.white60,
113 | fontSize: 11,
114 | decoration: TextDecoration.underline,
115 | ),
116 | ),
117 | ),
118 | ],
119 | ),
120 | SizedBox(height: 4),
121 | ],
122 | ),
123 | ),
124 | widget.submissionData.isSelf || widget.isViewingPost
125 | ? Container()
126 | : _buildPostThumbnail(
127 | widget.submissionData.preview,
128 | screenWidth,
129 | ),
130 | if (widget.selfText != null && widget.selfText.isNotEmpty)
131 | _buildSelfText(),
132 | ],
133 | ),
134 | _buildBottomBar(context),
135 | ],
136 | ),
137 | ),
138 | ),
139 | );
140 | }
141 |
142 | Future _upVote() async {
143 | // TODO: Setup API call such that it cant be spammed
144 | setState(() {
145 | voteStatus = VoteState.upvoted;
146 | });
147 | }
148 |
149 | Future _downVote() async {
150 | // TODO: Setup API call such that it cant be spammed
151 | setState(() {
152 | voteStatus = VoteState.downvoted;
153 | });
154 | }
155 |
156 | Future _copyPostUrl(BuildContext context) async {
157 | Clipboard.setData(
158 | ClipboardData(text: widget.submissionData.url.toString()));
159 | await showPopupDialog(context: context, dialogMessage: 'Copied Link');
160 | }
161 |
162 | Widget _buildBottomBar(BuildContext context) {
163 | return Row(
164 | mainAxisAlignment: MainAxisAlignment.start,
165 | children: [
166 | if (!widget.isViewingPost)
167 | IconButton(
168 | icon: Icon(
169 | EvaIcons.messageSquareOutline,
170 | ),
171 | onPressed: () {
172 | if (widget.onCommentTap != null) widget.onCommentTap();
173 | },
174 | ),
175 | if (!widget.isViewingPost && widget.isLoggedIn)
176 | IconButton(
177 | icon: Icon(
178 | Icons.keyboard_arrow_up,
179 | color: widget.submissionData.vote == VoteState.upvoted ||
180 | voteStatus == VoteState.upvoted
181 | ? Colors.red
182 | : Colors.white,
183 | ),
184 | onPressed: () {
185 | _upVote();
186 | },
187 | ),
188 | if (!widget.isViewingPost && widget.isLoggedIn)
189 | IconButton(
190 | icon: Icon(
191 | Icons.keyboard_arrow_down,
192 | color: widget.submissionData.vote == VoteState.downvoted ||
193 | voteStatus == VoteState.downvoted
194 | ? Colors.red
195 | : Colors.white,
196 | ),
197 | onPressed: () {
198 | _downVote();
199 | },
200 | ),
201 | IconButton(
202 | icon: Icon(Icons.content_copy),
203 | onPressed: () {
204 | _copyPostUrl(context);
205 | },
206 | ),
207 | ],
208 | );
209 | }
210 |
211 | Widget _buildPostThumbnail(
212 | List thumbnails, double screenWidth) {
213 | if (thumbnails != null && thumbnails.isNotEmpty) {
214 | var image = thumbnails.first.resolutions.last;
215 | var imageResolution = image.height / image.width;
216 | return FadeInImage.memoryNetwork(
217 | fadeInDuration: Duration(milliseconds: 200),
218 | placeholder: kTransparentImage,
219 | image: image.url.toString(),
220 | width: screenWidth,
221 | fit: BoxFit.fitWidth,
222 | height: imageResolution * screenWidth,
223 | );
224 | }
225 | return Container();
226 | }
227 |
228 | Widget _buildSelfText() {
229 | return SingleChildScrollView(
230 | scrollDirection: Axis.horizontal,
231 | padding: EdgeInsets.all(10),
232 | child: IntrinsicHeight(
233 | child: MarkdownBody(
234 | styleSheet: MarkdownStyleSheet(
235 | p: GoogleFonts.inter(
236 | fontSize: 13,
237 | ),
238 | h1: GoogleFonts.inter(
239 | fontSize: 16,
240 | ),
241 | h2: GoogleFonts.inter(
242 | fontSize: 19,
243 | ),
244 | h3: GoogleFonts.inter(
245 | fontSize: 22,
246 | ),
247 | tableHead: TextStyle(fontWeight: FontWeight.bold),
248 | tableBody: GoogleFonts.ptMono(),
249 | tableColumnWidth: IntrinsicColumnWidth(),
250 | ),
251 | data: widget.submissionData.selftext,
252 | extensionSet:
253 | md.ExtensionSet(md.ExtensionSet.gitHubWeb.blockSyntaxes, [
254 | md.EmojiSyntax(),
255 | ...md.ExtensionSet.gitHubFlavored.inlineSyntaxes,
256 | ]),
257 | onTapLink: (String url) async {
258 | await launchURL(url);
259 | },
260 | ),
261 | ),
262 | );
263 | }
264 | }
265 |
--------------------------------------------------------------------------------
/lib/drawer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 |
4 | class SubDrawer extends StatelessWidget {
5 | final void Function(String enteredText) onSubmitted;
6 | final void Function(String subreddit) onSavedSubredditTap;
7 | final void Function(String subreddit) onDeleteSubredditTap;
8 | final List savedSubs;
9 |
10 | const SubDrawer({
11 | this.onSubmitted,
12 | this.onSavedSubredditTap,
13 | this.onDeleteSubredditTap,
14 | this.savedSubs,
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Drawer(
20 | child: Container(
21 | color: Color(0xFF121212),
22 | child: ListView(
23 | children: [
24 | Padding(
25 | padding: EdgeInsets.all(10),
26 | child: TextField(
27 | onSubmitted: (String enteredText) {
28 | onSubmitted(enteredText);
29 | },
30 | decoration: InputDecoration(
31 | focusedBorder: OutlineInputBorder(
32 | borderSide: BorderSide(color: Colors.blueGrey, width: 2.0),
33 | ),
34 | enabledBorder: OutlineInputBorder(
35 | borderSide: BorderSide(color: Colors.blueGrey, width: 2.0),
36 | ),
37 | hintText: 'Enter a subreddit',
38 | hintStyle: GoogleFonts.inter(),
39 | ),
40 | ),
41 | ),
42 | ..._buildSavedSubs(),
43 | ],
44 | ),
45 | ),
46 | );
47 | }
48 |
49 | List _buildSavedSubs() {
50 | List widgetSubs = [];
51 | if (savedSubs != null) {
52 | for (var sub in savedSubs) {
53 | widgetSubs.add(
54 | _buildSavedSub(sub),
55 | );
56 | }
57 | }
58 | return widgetSubs;
59 | }
60 |
61 | Widget _buildSavedSub(String title) {
62 | return Material(
63 | color: Color(0xFF121212),
64 | child: ListTile(
65 | title: Text(
66 | 'r/$title',
67 | style: GoogleFonts.inter(),
68 | ),
69 | trailing: IconButton(
70 | icon: Icon(Icons.remove),
71 | onPressed: () {
72 | onDeleteSubredditTap(title);
73 | },
74 | ),
75 | onTap: () {
76 | onSavedSubredditTap(title);
77 | },
78 | ),
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/services.dart';
5 | import 'package:flutter_mobx/flutter_mobx.dart';
6 | import 'package:flutterreddit/common/loadingPostIndicator.dart';
7 | import 'package:flutterreddit/common/popupMenu.dart';
8 | import 'package:flutterreddit/common/config.dart';
9 | import 'package:flutterreddit/common/pullToRefresh.dart';
10 | import 'package:google_fonts/google_fonts.dart';
11 | import 'dart:io';
12 | import 'package:shared_preferences/shared_preferences.dart';
13 | import 'package:flutterreddit/mainpage_viewmodel.dart';
14 | import 'package:flutterreddit/common/subredditPost.dart';
15 | import 'package:flutterreddit/drawer.dart';
16 | import 'package:flutterreddit/common/launchURL.dart';
17 |
18 | Future main() async {
19 | WidgetsFlutterBinding.ensureInitialized();
20 |
21 | Config config = Config(
22 | isAndroid: Platform.isAndroid,
23 | sharedPreferences: await SharedPreferences.getInstance(),
24 | );
25 |
26 | runApp(MaterialApp(
27 | title: 'Retter',
28 | theme: ThemeData(
29 | brightness: Brightness.dark,
30 | primaryColor: Color(0xFF030303),
31 | accentColor: Colors.blueAccent,
32 | splashColor: Colors.blueGrey,
33 | ),
34 | home: MainPage(
35 | viewModel: MainPageViewModel(
36 | reddit: await config.onAppOpenLogin(),
37 | config: config,
38 | ),
39 | ),
40 | ));
41 | }
42 |
43 | class MainPage extends StatelessWidget {
44 | final MainPageViewModel viewModel;
45 |
46 | const MainPage({this.viewModel});
47 |
48 | @override
49 | Widget build(BuildContext context) {
50 | return Observer(builder: (_) {
51 | return Scaffold(
52 | backgroundColor: Color(0xFF121212),
53 | resizeToAvoidBottomInset: false,
54 | drawer: _buildDrawer(context),
55 | body: _buildCustomScrollView(context),
56 | );
57 | });
58 | }
59 |
60 | Widget _buildDrawer(BuildContext context) {
61 | return Observer(builder: (_) {
62 | return SubDrawer(
63 | savedSubs: viewModel.savedSubs,
64 | onSavedSubredditTap: (String subredditClicked) {
65 | viewModel.changeToSubreddit(subredditClicked);
66 | Navigator.pop(context);
67 | },
68 | onSubmitted: (String enteredText) {
69 | viewModel.changeToSubreddit(enteredText);
70 | Navigator.pop(context);
71 | },
72 | onDeleteSubredditTap: (String subredditDeleted) {
73 | viewModel.deleteSubreddit(subredditDeleted);
74 | },
75 | );
76 | });
77 | }
78 |
79 | Widget _buildTitle() {
80 | return Observer(builder: (_) {
81 | return Text(
82 | 'r/${viewModel.currentSubreddit != null ? viewModel.currentSubreddit.displayName : viewModel.defaultSubredditString}',
83 | style: GoogleFonts.inter(),
84 | );
85 | });
86 | }
87 |
88 | Widget _buildCustomScrollView(BuildContext context) {
89 | return CustomScrollView(
90 | physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
91 | controller: viewModel.scrollController,
92 | slivers: [
93 | SliverAppBar(
94 | floating: true,
95 | flexibleSpace: FlexibleSpaceBar(
96 | title: _buildTitle(),
97 | ),
98 | actions: [
99 | Observer(builder: (_) {
100 | return CustomPopupMenu(
101 | isLoggedIn: viewModel?.redditor != null,
102 | onTap: (popupMenuOptions optionSelected) async {
103 | switch (optionSelected) {
104 | case popupMenuOptions.Login:
105 | await viewModel.login();
106 | break;
107 | case popupMenuOptions.Logout:
108 | await viewModel.logout();
109 | break;
110 | }
111 | },
112 | );
113 | }),
114 | ],
115 | ),
116 | CupertinoSliverRefreshControl(
117 | builder: (
118 | BuildContext context,
119 | RefreshIndicatorMode refreshState,
120 | double pulledExtent,
121 | double refreshTriggerPullDistance,
122 | double refreshIndicatorExtent,
123 | ) {
124 | return buildPullToRefresh(
125 | context,
126 | refreshState,
127 | pulledExtent,
128 | refreshTriggerPullDistance,
129 | refreshIndicatorExtent,
130 | );
131 | },
132 | onRefresh: () async {
133 | viewModel.refreshPosts();
134 | },
135 | ),
136 | if (viewModel.loadedPostSuccessfully) _buildPosts(context),
137 | ],
138 | );
139 | }
140 |
141 | Widget _buildPosts(BuildContext context) {
142 | return Observer(builder: (_) {
143 | return SliverList(
144 | delegate: SliverChildListDelegate(
145 | List.generate(viewModel.submissionContent.length + 1, (index) {
146 | var isLastIndex = index == viewModel.submissionContent.length;
147 | if (isLastIndex && !viewModel.hasLoadedAllAvailablePosts) {
148 | return buildLoadingPostIndicator('Loading posts...');
149 | } else if (isLastIndex && viewModel.hasLoadedAllAvailablePosts) {
150 | return Container();
151 | }
152 |
153 | var submissionData = viewModel.submissionContent.elementAt(index);
154 | return SubredditPost(
155 | context: context,
156 | submissionData: submissionData,
157 | isViewingPost: false,
158 | isLoggedIn: viewModel?.redditor != null,
159 | onSubredditTap: (String enteredText) {
160 | viewModel.changeToSubreddit(enteredText);
161 | },
162 | onProfileTap: (String username) {
163 | // TODO: Setup profile page
164 | // viewModel.goToProfilePage(
165 | // context,
166 | // username,
167 | // );
168 | },
169 | onTap: () async {
170 | if (submissionData.isSelf) {
171 | viewModel.goToPostPage(
172 | context,
173 | submissionData,
174 | viewModel.changeToSubreddit,
175 | (String username) {
176 | // TODO: setup profile page
177 | // viewModel.goToProfilePage(context, username);
178 | },
179 | );
180 | } else {
181 | await launchURL(submissionData.url.toString());
182 | }
183 | },
184 | onCommentTap: () {
185 | viewModel.goToPostPage(
186 | context,
187 | submissionData,
188 | viewModel.changeToSubreddit,
189 | (String username) {
190 | // TODO: go to profile page
191 | // viewModel.goToProfilePage(context, username);
192 | },
193 | );
194 | },
195 | );
196 | }),
197 | ),
198 | );
199 | });
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/lib/mainpage_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:draw/draw.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:flutterreddit/postpage.dart';
5 | import 'package:flutterreddit/postpage_viewmodel.dart';
6 | import 'package:flutterreddit/profilepage.dart';
7 | import 'package:flutterreddit/profilepage_viewmodel.dart';
8 | import 'package:mobx/mobx.dart';
9 | import 'package:flutter/foundation.dart';
10 | import 'package:flutterreddit/common/config.dart';
11 |
12 | part 'mainpage_viewmodel.g.dart';
13 |
14 | class MainPageViewModel = MainPageViewModelBase with _$MainPageViewModel;
15 |
16 | abstract class MainPageViewModelBase with Store {
17 | final Config config;
18 | final ScrollController scrollController = ScrollController();
19 | final String defaultSubredditString = 'All';
20 | final int _numberOfPostsToFetch = 25;
21 |
22 | MainPageViewModelBase({
23 | @required this.reddit,
24 | @required this.config,
25 | }) {
26 | _initPage();
27 | }
28 |
29 | @observable
30 | Reddit reddit;
31 |
32 | @observable
33 | Redditor redditor;
34 |
35 | @observable
36 | String expandedPost;
37 |
38 | @observable
39 | List savedSubs = ObservableList();
40 |
41 | @observable
42 | List submissionContent = ObservableList();
43 |
44 | @observable
45 | SubredditRef currentSubreddit;
46 |
47 | @observable
48 | bool loadedPostSuccessfully = true;
49 |
50 | @observable
51 | bool hasLoadedAllAvailablePosts = false;
52 |
53 | void goToPostPage(
54 | BuildContext context,
55 | Submission submission,
56 | Function(String) goToSubreddit,
57 | Function(String) goToProfile,
58 | ) {
59 | Navigator.push(
60 | context,
61 | MaterialPageRoute(
62 | builder: (BuildContext context) => PostPage(
63 | viewModel: PostPageViewModel(
64 | submission: submission,
65 | goToSubreddit: goToSubreddit,
66 | goToProfile: goToProfile,
67 | ),
68 | ),
69 | ),
70 | );
71 | }
72 |
73 | void goToProfilePage(
74 | BuildContext context,
75 | String username,
76 | ) {
77 | Navigator.push(
78 | context,
79 | MaterialPageRoute(
80 | builder: (BuildContext context) => ProfilePage(
81 | viewModel: ProfilePageViewModel(),
82 | ),
83 | ),
84 | );
85 | }
86 |
87 | void changeToSubreddit(String subredditTextField) async {
88 | if (currentSubreddit.displayName.toLowerCase() ==
89 | subredditTextField.toLowerCase() &&
90 | subredditTextField != defaultSubredditString) {
91 | return;
92 | }
93 | submissionContent.clear();
94 | currentSubreddit = reddit.subreddit(subredditTextField);
95 | hasLoadedAllAvailablePosts = false;
96 |
97 | loadedPostSuccessfully = true;
98 | loadedPostSuccessfully = await _getPosts(currentSubreddit);
99 | if (loadedPostSuccessfully) {
100 | savedSubs = ObservableList.of(config.saveSubreddit(subredditTextField));
101 | }
102 | }
103 |
104 | void deleteSubreddit(String subredditToDelete) {
105 | savedSubs = ObservableList.of(config.deleteSubreddit(subredditToDelete));
106 | }
107 |
108 | Future login() async {
109 | if (redditor == null) {
110 | await config.login((Reddit redditResponse) async {
111 | if (redditResponse != null) {
112 | reddit = redditResponse;
113 | await getRedditor();
114 | }
115 | });
116 | }
117 | }
118 |
119 | Future logout() async {
120 | if (redditor != null) {
121 | await config.logout((Reddit redditResponse) async {
122 | if (redditResponse != null) {
123 | reddit = redditResponse;
124 | redditor = null;
125 | config.deleteLoginDetails();
126 | }
127 | });
128 | }
129 | }
130 |
131 | Future refreshPosts() async {
132 | submissionContent.clear();
133 | hasLoadedAllAvailablePosts = false;
134 | loadedPostSuccessfully = true;
135 | loadedPostSuccessfully = await _getPosts(currentSubreddit);
136 | }
137 |
138 | void _initPage() async {
139 | await getRedditor();
140 |
141 | _setDefaultSubreddit();
142 |
143 | changeToSubreddit(defaultSubredditString);
144 |
145 | _initScrollController();
146 | }
147 |
148 | SubredditRef _setDefaultSubreddit() {
149 | return currentSubreddit = reddit.subreddit('All');
150 | }
151 |
152 | Future _getPosts(SubredditRef subredditToFetchFrom) async {
153 | if (!hasLoadedAllAvailablePosts)
154 | try {
155 | var subreddit = subredditToFetchFrom.hot(
156 | after: submissionContent.isNotEmpty
157 | ? submissionContent.last.fullname
158 | : null,
159 | limit: _numberOfPostsToFetch);
160 |
161 | var posts = await subreddit.toList();
162 | hasLoadedAllAvailablePosts = posts.length != _numberOfPostsToFetch;
163 | for (UserContent post in posts) {
164 | Submission submission = post;
165 | submissionContent.add(submission);
166 | }
167 | return true;
168 | } catch (_) {
169 | return false;
170 | }
171 | return true;
172 | }
173 |
174 | void _initScrollController() {
175 | scrollController.addListener(() {
176 | if (scrollController.position.pixels ==
177 | scrollController.position.maxScrollExtent &&
178 | !hasLoadedAllAvailablePosts) {
179 | _getPosts(currentSubreddit);
180 | }
181 | });
182 | }
183 |
184 | Future getRedditor() async {
185 | try {
186 | redditor = await reddit.user.me();
187 | } catch (e) {
188 | // TODO: handle this error
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/lib/mainpage_viewmodel.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'mainpage_viewmodel.dart';
4 |
5 | // **************************************************************************
6 | // StoreGenerator
7 | // **************************************************************************
8 |
9 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
10 |
11 | mixin _$MainPageViewModel on MainPageViewModelBase, Store {
12 | final _$redditAtom = Atom(name: 'MainPageViewModelBase.reddit');
13 |
14 | @override
15 | Reddit get reddit {
16 | _$redditAtom.reportRead();
17 | return super.reddit;
18 | }
19 |
20 | @override
21 | set reddit(Reddit value) {
22 | _$redditAtom.reportWrite(value, super.reddit, () {
23 | super.reddit = value;
24 | });
25 | }
26 |
27 | final _$redditorAtom = Atom(name: 'MainPageViewModelBase.redditor');
28 |
29 | @override
30 | Redditor get redditor {
31 | _$redditorAtom.reportRead();
32 | return super.redditor;
33 | }
34 |
35 | @override
36 | set redditor(Redditor value) {
37 | _$redditorAtom.reportWrite(value, super.redditor, () {
38 | super.redditor = value;
39 | });
40 | }
41 |
42 | final _$expandedPostAtom = Atom(name: 'MainPageViewModelBase.expandedPost');
43 |
44 | @override
45 | String get expandedPost {
46 | _$expandedPostAtom.reportRead();
47 | return super.expandedPost;
48 | }
49 |
50 | @override
51 | set expandedPost(String value) {
52 | _$expandedPostAtom.reportWrite(value, super.expandedPost, () {
53 | super.expandedPost = value;
54 | });
55 | }
56 |
57 | final _$savedSubsAtom = Atom(name: 'MainPageViewModelBase.savedSubs');
58 |
59 | @override
60 | List get savedSubs {
61 | _$savedSubsAtom.reportRead();
62 | return super.savedSubs;
63 | }
64 |
65 | @override
66 | set savedSubs(List value) {
67 | _$savedSubsAtom.reportWrite(value, super.savedSubs, () {
68 | super.savedSubs = value;
69 | });
70 | }
71 |
72 | final _$submissionContentAtom =
73 | Atom(name: 'MainPageViewModelBase.submissionContent');
74 |
75 | @override
76 | List get submissionContent {
77 | _$submissionContentAtom.reportRead();
78 | return super.submissionContent;
79 | }
80 |
81 | @override
82 | set submissionContent(List value) {
83 | _$submissionContentAtom.reportWrite(value, super.submissionContent, () {
84 | super.submissionContent = value;
85 | });
86 | }
87 |
88 | final _$currentSubredditAtom =
89 | Atom(name: 'MainPageViewModelBase.currentSubreddit');
90 |
91 | @override
92 | SubredditRef get currentSubreddit {
93 | _$currentSubredditAtom.reportRead();
94 | return super.currentSubreddit;
95 | }
96 |
97 | @override
98 | set currentSubreddit(SubredditRef value) {
99 | _$currentSubredditAtom.reportWrite(value, super.currentSubreddit, () {
100 | super.currentSubreddit = value;
101 | });
102 | }
103 |
104 | final _$loadedPostSuccessfullyAtom =
105 | Atom(name: 'MainPageViewModelBase.loadedPostSuccessfully');
106 |
107 | @override
108 | bool get loadedPostSuccessfully {
109 | _$loadedPostSuccessfullyAtom.reportRead();
110 | return super.loadedPostSuccessfully;
111 | }
112 |
113 | @override
114 | set loadedPostSuccessfully(bool value) {
115 | _$loadedPostSuccessfullyAtom
116 | .reportWrite(value, super.loadedPostSuccessfully, () {
117 | super.loadedPostSuccessfully = value;
118 | });
119 | }
120 |
121 | final _$hasLoadedAllAvailablePostsAtom =
122 | Atom(name: 'MainPageViewModelBase.hasLoadedAllAvailablePosts');
123 |
124 | @override
125 | bool get hasLoadedAllAvailablePosts {
126 | _$hasLoadedAllAvailablePostsAtom.reportRead();
127 | return super.hasLoadedAllAvailablePosts;
128 | }
129 |
130 | @override
131 | set hasLoadedAllAvailablePosts(bool value) {
132 | _$hasLoadedAllAvailablePostsAtom
133 | .reportWrite(value, super.hasLoadedAllAvailablePosts, () {
134 | super.hasLoadedAllAvailablePosts = value;
135 | });
136 | }
137 |
138 | @override
139 | String toString() {
140 | return '''
141 | reddit: ${reddit},
142 | redditor: ${redditor},
143 | expandedPost: ${expandedPost},
144 | savedSubs: ${savedSubs},
145 | submissionContent: ${submissionContent},
146 | currentSubreddit: ${currentSubreddit},
147 | loadedPostSuccessfully: ${loadedPostSuccessfully},
148 | hasLoadedAllAvailablePosts: ${hasLoadedAllAvailablePosts}
149 | ''';
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/lib/postpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_markdown/flutter_markdown.dart';
4 | import 'package:flutter_mobx/flutter_mobx.dart';
5 | import 'package:flutter/foundation.dart';
6 | import 'package:flutterreddit/common/launchURL.dart';
7 | import 'package:flutterreddit/common/loadingPostIndicator.dart';
8 | import 'package:flutterreddit/postpage_viewmodel.dart';
9 | import 'package:flutterreddit/common/subredditPost.dart';
10 | import 'package:google_fonts/google_fonts.dart';
11 |
12 | class PostPage extends StatelessWidget {
13 | final PostPageViewModel viewModel;
14 |
15 | const PostPage({
16 | @required this.viewModel,
17 | });
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Observer(builder: (_) {
22 | return Scaffold(
23 | backgroundColor: Color(0xFF121212),
24 | appBar: AppBar(
25 | leading: IconButton(
26 | icon: Icon(
27 | Icons.arrow_back_ios,
28 | ),
29 | onPressed: () {
30 | Navigator.pop(context);
31 | },
32 | ),
33 | ),
34 | body: ListView(
35 | children: [
36 | SubredditPost(
37 | context: context,
38 | submissionData: viewModel.submission,
39 | isViewingPost: true,
40 | selfText:
41 | viewModel.isSelfPost() ? viewModel.submission.selftext : '',
42 | onTap: () async {
43 | if (!viewModel.submission.isSelf) {
44 | await launchURL(viewModel.submission.url.toString());
45 | }
46 | },
47 | onSubredditTap: viewModel.goToSubreddit,
48 | onProfileTap: (String username) {
49 | Navigator.pop(context);
50 | viewModel.goToProfile(
51 | username,
52 | );
53 | },
54 | ),
55 | viewModel.loadingComments
56 | ? buildLoadingPostIndicator('Loading comments...')
57 | : _buildComments(),
58 | ],
59 | ),
60 | );
61 | });
62 | }
63 |
64 | Widget _buildComments() {
65 | return Observer(builder: (_) {
66 | return ListView.builder(
67 | shrinkWrap: true,
68 | physics: ScrollPhysics(),
69 | itemCount: viewModel.comments.length,
70 | itemBuilder: (BuildContext context, int index) {
71 | return _buildComment(viewModel.comments[index], index);
72 | },
73 | );
74 | });
75 | }
76 |
77 | Widget _buildComment(PageComment comment, int index) {
78 | return Observer(builder: (_) {
79 | if (comment.isBelowCollapsed) {
80 | return Container();
81 | } else if (comment.isCollapsed) {
82 | return GestureDetector(
83 | onTap: () {
84 | viewModel.unCollapseNestedComments(index);
85 | },
86 | child: Card(
87 | elevation: 0,
88 | color: Colors.transparent,
89 | margin:
90 | EdgeInsets.fromLTRB(5.0 * comment.commentLevel, 5.0, 5.0, 5.0),
91 | child: Padding(
92 | padding: EdgeInsets.all(5),
93 | child: Column(
94 | crossAxisAlignment: CrossAxisAlignment.start,
95 | children: [
96 | Row(
97 | children: [
98 | Icon(
99 | Icons.keyboard_arrow_right,
100 | size: 20,
101 | ),
102 | Text(
103 | comment.commentData.author,
104 | style: GoogleFonts.inter(
105 | color: Colors.blueGrey,
106 | fontWeight: FontWeight.w300,
107 | fontSize: 13,
108 | ),
109 | ),
110 | ],
111 | ),
112 | ],
113 | ),
114 | ),
115 | ),
116 | );
117 | } else {
118 | return GestureDetector(
119 | onTap: () {
120 | viewModel.collapseNestedComments(index);
121 | },
122 | child: Container(
123 | margin:
124 | EdgeInsets.fromLTRB(5.0 * comment.commentLevel, 5.0, 5.0, 5.0),
125 | child: Padding(
126 | padding: EdgeInsets.all(5),
127 | child: Column(
128 | crossAxisAlignment: CrossAxisAlignment.start,
129 | children: [
130 | Row(
131 | children: [
132 | Icon(
133 | Icons.keyboard_arrow_down,
134 | size: 20,
135 | ),
136 | Text(
137 | comment.commentData.author,
138 | style: GoogleFonts.inter(
139 | color: Colors.blueGrey,
140 | fontWeight: FontWeight.w300,
141 | fontSize: 13,
142 | ),
143 | ),
144 | ],
145 | ),
146 | MarkdownBody(
147 | styleSheet: MarkdownStyleSheet(
148 | p: GoogleFonts.inter(
149 | fontSize: 12,
150 | ),
151 | h1: GoogleFonts.inter(
152 | fontSize: 13,
153 | ),
154 | h2: GoogleFonts.inter(
155 | fontSize: 14,
156 | ),
157 | h3: GoogleFonts.inter(
158 | fontSize: 15,
159 | ),
160 | ),
161 | data: comment.commentData.body,
162 | onTapLink: (String url) async {
163 | await launchURL(url);
164 | },
165 | ),
166 | ],
167 | ),
168 | ),
169 | ),
170 | );
171 | }
172 | });
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/lib/postpage_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:draw/draw.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:mobx/mobx.dart';
5 | import 'package:flutter/foundation.dart';
6 |
7 | part 'postpage_viewmodel.g.dart';
8 |
9 | class PostPageViewModel = PostPageViewModelBase with _$PostPageViewModel;
10 | class PageComment = PageCommentModelBase with _$PageComment;
11 |
12 | abstract class PageCommentModelBase with Store {
13 | final Comment commentData;
14 | final int commentLevel;
15 |
16 | @observable
17 | bool isCollapsed = false;
18 |
19 | @observable
20 | bool isBelowCollapsed = false;
21 |
22 | PageCommentModelBase({
23 | this.commentData,
24 | this.commentLevel,
25 | });
26 | }
27 |
28 | abstract class PostPageViewModelBase with Store {
29 | final Submission submission;
30 | final Function(String) goToSubreddit;
31 | final Function(String) goToProfile;
32 |
33 | @observable
34 | bool loadingComments = false;
35 |
36 | @observable
37 | List comments = [];
38 |
39 | PostPageViewModelBase({
40 | @required this.submission,
41 | @required this.goToSubreddit,
42 | @required this.goToProfile,
43 | }) {
44 | getComments();
45 | }
46 |
47 | bool isSelfPost() {
48 | return submission.isSelf &&
49 | submission.selftext != null &&
50 | submission.selftext.isNotEmpty;
51 | }
52 |
53 | Future getComments() async {
54 | loadingComments = true;
55 | await submission.refreshComments();
56 |
57 | List postComments = [];
58 | if (submission.comments != null && submission.comments.comments != null) {
59 | _getNestedComments(submission.comments.comments, postComments, 0);
60 | }
61 |
62 | comments = ObservableList.of(postComments);
63 | loadingComments = false;
64 | }
65 |
66 | void collapseNestedComments(int index) {
67 | // Collapse clicked on comment
68 | comments[index].isCollapsed = true;
69 |
70 | // Mark comments below the collapsed comment as "isBelowCollapsed" which will completely
71 | // remove them from the screen
72 | int collapseCommentIndex = index + 1;
73 | for (int i = collapseCommentIndex; i < comments.length; ++i) {
74 | if (comments[index].commentLevel < comments[i].commentLevel) {
75 | comments[i].isBelowCollapsed = true;
76 | } else {
77 | break;
78 | }
79 | }
80 | }
81 |
82 | void unCollapseNestedComments(int index) {
83 | // UnCollapse clicked on comment
84 | comments[index].isCollapsed = false;
85 |
86 | // Mark comments below the collapsed comment as not "isBelowCollapsed" which will
87 | // reveal the comments again
88 | int collapseCommentIndex = index + 1;
89 | for (int i = collapseCommentIndex; i < comments.length; ++i) {
90 | if (comments[index].commentLevel < comments[i].commentLevel) {
91 | comments[i].isBelowCollapsed = false;
92 | } else {
93 | break;
94 | }
95 | }
96 | }
97 |
98 | void _getNestedComments(
99 | List commentList, List pageCommentList, int level) {
100 | level += 1;
101 | for (var comment in commentList) {
102 | if (comment is Comment) {
103 | pageCommentList
104 | .add(PageComment(commentData: comment, commentLevel: level));
105 |
106 | if (comment.replies != null) {
107 | _getNestedComments(comment.replies.comments, pageCommentList, level);
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/postpage_viewmodel.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'postpage_viewmodel.dart';
4 |
5 | // **************************************************************************
6 | // StoreGenerator
7 | // **************************************************************************
8 |
9 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
10 |
11 | mixin _$PageComment on PageCommentModelBase, Store {
12 | final _$isCollapsedAtom = Atom(name: 'PageCommentModelBase.isCollapsed');
13 |
14 | @override
15 | bool get isCollapsed {
16 | _$isCollapsedAtom.reportRead();
17 | return super.isCollapsed;
18 | }
19 |
20 | @override
21 | set isCollapsed(bool value) {
22 | _$isCollapsedAtom.reportWrite(value, super.isCollapsed, () {
23 | super.isCollapsed = value;
24 | });
25 | }
26 |
27 | final _$isBelowCollapsedAtom =
28 | Atom(name: 'PageCommentModelBase.isBelowCollapsed');
29 |
30 | @override
31 | bool get isBelowCollapsed {
32 | _$isBelowCollapsedAtom.reportRead();
33 | return super.isBelowCollapsed;
34 | }
35 |
36 | @override
37 | set isBelowCollapsed(bool value) {
38 | _$isBelowCollapsedAtom.reportWrite(value, super.isBelowCollapsed, () {
39 | super.isBelowCollapsed = value;
40 | });
41 | }
42 |
43 | @override
44 | String toString() {
45 | return '''
46 | isCollapsed: ${isCollapsed},
47 | isBelowCollapsed: ${isBelowCollapsed}
48 | ''';
49 | }
50 | }
51 |
52 | mixin _$PostPageViewModel on PostPageViewModelBase, Store {
53 | final _$loadingCommentsAtom =
54 | Atom(name: 'PostPageViewModelBase.loadingComments');
55 |
56 | @override
57 | bool get loadingComments {
58 | _$loadingCommentsAtom.reportRead();
59 | return super.loadingComments;
60 | }
61 |
62 | @override
63 | set loadingComments(bool value) {
64 | _$loadingCommentsAtom.reportWrite(value, super.loadingComments, () {
65 | super.loadingComments = value;
66 | });
67 | }
68 |
69 | final _$commentsAtom = Atom(name: 'PostPageViewModelBase.comments');
70 |
71 | @override
72 | List get comments {
73 | _$commentsAtom.reportRead();
74 | return super.comments;
75 | }
76 |
77 | @override
78 | set comments(List value) {
79 | _$commentsAtom.reportWrite(value, super.comments, () {
80 | super.comments = value;
81 | });
82 | }
83 |
84 | @override
85 | String toString() {
86 | return '''
87 | loadingComments: ${loadingComments},
88 | comments: ${comments}
89 | ''';
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/profilepage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_mobx/flutter_mobx.dart';
3 | import 'package:flutterreddit/profilepage_viewmodel.dart';
4 |
5 | class ProfilePage extends StatelessWidget {
6 | final ProfilePageViewModel viewModel;
7 |
8 | const ProfilePage({
9 | @required this.viewModel,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Observer(builder: (_) {
15 | return Scaffold(
16 | backgroundColor: Color(0xFF121212),
17 | appBar: AppBar(
18 | title: Text('username here'),
19 | leading: IconButton(
20 | icon: Icon(
21 | Icons.arrow_back_ios,
22 | ),
23 | onPressed: () {
24 | Navigator.pop(context);
25 | },
26 | ),
27 | ),
28 | body: ListView(
29 | children: [
30 | Container(),
31 | ],
32 | ),
33 | );
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/profilepage_viewmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:mobx/mobx.dart';
3 |
4 | part 'profilepage_viewmodel.g.dart';
5 |
6 | class ProfilePageViewModel = ProfilePageViewModelBase
7 | with _$ProfilePageViewModel;
8 |
9 | abstract class ProfilePageViewModelBase with Store {}
10 |
--------------------------------------------------------------------------------
/lib/profilepage_viewmodel.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'profilepage_viewmodel.dart';
4 |
5 | // **************************************************************************
6 | // StoreGenerator
7 | // **************************************************************************
8 |
9 | // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
10 |
11 | mixin _$ProfilePageViewModel on ProfilePageViewModelBase, Store {
12 | @override
13 | String toString() {
14 | return '''
15 |
16 | ''';
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "6.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "0.39.14"
18 | archive:
19 | dependency: transitive
20 | description:
21 | name: archive
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.0.13"
25 | args:
26 | dependency: transitive
27 | description:
28 | name: args
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.6.0"
32 | async:
33 | dependency: transitive
34 | description:
35 | name: async
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.4.2"
39 | boolean_selector:
40 | dependency: transitive
41 | description:
42 | name: boolean_selector
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "2.0.0"
46 | build:
47 | dependency: transitive
48 | description:
49 | name: build
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.3.0"
53 | build_config:
54 | dependency: transitive
55 | description:
56 | name: build_config
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.4.2"
60 | build_daemon:
61 | dependency: transitive
62 | description:
63 | name: build_daemon
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "2.1.4"
67 | build_resolvers:
68 | dependency: transitive
69 | description:
70 | name: build_resolvers
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "1.3.11"
74 | build_runner:
75 | dependency: "direct main"
76 | description:
77 | name: build_runner
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.10.1"
81 | build_runner_core:
82 | dependency: transitive
83 | description:
84 | name: build_runner_core
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "6.0.1"
88 | built_collection:
89 | dependency: transitive
90 | description:
91 | name: built_collection
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "4.3.2"
95 | built_value:
96 | dependency: transitive
97 | description:
98 | name: built_value
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "7.1.0"
102 | characters:
103 | dependency: transitive
104 | description:
105 | name: characters
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "1.0.0"
109 | charcode:
110 | dependency: transitive
111 | description:
112 | name: charcode
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "1.1.3"
116 | checked_yaml:
117 | dependency: transitive
118 | description:
119 | name: checked_yaml
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "1.0.2"
123 | cli_util:
124 | dependency: transitive
125 | description:
126 | name: cli_util
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "0.1.4"
130 | clock:
131 | dependency: transitive
132 | description:
133 | name: clock
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "1.0.1"
137 | code_builder:
138 | dependency: transitive
139 | description:
140 | name: code_builder
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "3.5.0"
144 | collection:
145 | dependency: transitive
146 | description:
147 | name: collection
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "1.14.13"
151 | color:
152 | dependency: transitive
153 | description:
154 | name: color
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "2.1.1"
158 | convert:
159 | dependency: transitive
160 | description:
161 | name: convert
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "2.1.1"
165 | crypto:
166 | dependency: transitive
167 | description:
168 | name: crypto
169 | url: "https://pub.dartlang.org"
170 | source: hosted
171 | version: "2.1.5"
172 | csslib:
173 | dependency: transitive
174 | description:
175 | name: csslib
176 | url: "https://pub.dartlang.org"
177 | source: hosted
178 | version: "0.16.2"
179 | cupertino_icons:
180 | dependency: "direct main"
181 | description:
182 | name: cupertino_icons
183 | url: "https://pub.dartlang.org"
184 | source: hosted
185 | version: "0.1.3"
186 | dart_style:
187 | dependency: transitive
188 | description:
189 | name: dart_style
190 | url: "https://pub.dartlang.org"
191 | source: hosted
192 | version: "1.3.6"
193 | draw:
194 | dependency: "direct main"
195 | description:
196 | name: draw
197 | url: "https://pub.dartlang.org"
198 | source: hosted
199 | version: "0.9.1"
200 | eva_icons_flutter:
201 | dependency: "direct main"
202 | description:
203 | name: eva_icons_flutter
204 | url: "https://pub.dartlang.org"
205 | source: hosted
206 | version: "2.0.1"
207 | fake_async:
208 | dependency: transitive
209 | description:
210 | name: fake_async
211 | url: "https://pub.dartlang.org"
212 | source: hosted
213 | version: "1.1.0"
214 | ffi:
215 | dependency: transitive
216 | description:
217 | name: ffi
218 | url: "https://pub.dartlang.org"
219 | source: hosted
220 | version: "0.1.3"
221 | file:
222 | dependency: transitive
223 | description:
224 | name: file
225 | url: "https://pub.dartlang.org"
226 | source: hosted
227 | version: "5.2.1"
228 | fixnum:
229 | dependency: transitive
230 | description:
231 | name: fixnum
232 | url: "https://pub.dartlang.org"
233 | source: hosted
234 | version: "0.10.11"
235 | flutter:
236 | dependency: "direct main"
237 | description: flutter
238 | source: sdk
239 | version: "0.0.0"
240 | flutter_launcher_icons:
241 | dependency: "direct dev"
242 | description:
243 | name: flutter_launcher_icons
244 | url: "https://pub.dartlang.org"
245 | source: hosted
246 | version: "0.7.5"
247 | flutter_markdown:
248 | dependency: "direct main"
249 | description:
250 | name: flutter_markdown
251 | url: "https://pub.dartlang.org"
252 | source: hosted
253 | version: "0.4.4"
254 | flutter_mobx:
255 | dependency: "direct main"
256 | description:
257 | name: flutter_mobx
258 | url: "https://pub.dartlang.org"
259 | source: hosted
260 | version: "1.1.0+2"
261 | flutter_test:
262 | dependency: "direct dev"
263 | description: flutter
264 | source: sdk
265 | version: "0.0.0"
266 | flutter_web_browser:
267 | dependency: "direct main"
268 | description:
269 | name: flutter_web_browser
270 | url: "https://pub.dartlang.org"
271 | source: hosted
272 | version: "0.11.0"
273 | flutter_web_plugins:
274 | dependency: transitive
275 | description: flutter
276 | source: sdk
277 | version: "0.0.0"
278 | flutter_webview_plugin:
279 | dependency: "direct main"
280 | description:
281 | name: flutter_webview_plugin
282 | url: "https://pub.dartlang.org"
283 | source: hosted
284 | version: "0.3.11"
285 | glob:
286 | dependency: transitive
287 | description:
288 | name: glob
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "1.2.0"
292 | google_fonts:
293 | dependency: "direct main"
294 | description:
295 | name: google_fonts
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "1.1.0"
299 | graphs:
300 | dependency: transitive
301 | description:
302 | name: graphs
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "0.2.0"
306 | html:
307 | dependency: transitive
308 | description:
309 | name: html
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "0.14.0+4"
313 | http:
314 | dependency: transitive
315 | description:
316 | name: http
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "0.12.2"
320 | http_multi_server:
321 | dependency: transitive
322 | description:
323 | name: http_multi_server
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "2.2.0"
327 | http_parser:
328 | dependency: transitive
329 | description:
330 | name: http_parser
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "3.1.4"
334 | image:
335 | dependency: transitive
336 | description:
337 | name: image
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "2.1.18"
341 | ini:
342 | dependency: transitive
343 | description:
344 | name: ini
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "2.0.1"
348 | intl:
349 | dependency: "direct main"
350 | description:
351 | name: intl
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "0.15.8"
355 | io:
356 | dependency: transitive
357 | description:
358 | name: io
359 | url: "https://pub.dartlang.org"
360 | source: hosted
361 | version: "0.3.4"
362 | js:
363 | dependency: transitive
364 | description:
365 | name: js
366 | url: "https://pub.dartlang.org"
367 | source: hosted
368 | version: "0.6.2"
369 | json_annotation:
370 | dependency: transitive
371 | description:
372 | name: json_annotation
373 | url: "https://pub.dartlang.org"
374 | source: hosted
375 | version: "3.1.0"
376 | logging:
377 | dependency: transitive
378 | description:
379 | name: logging
380 | url: "https://pub.dartlang.org"
381 | source: hosted
382 | version: "0.11.4"
383 | markdown:
384 | dependency: transitive
385 | description:
386 | name: markdown
387 | url: "https://pub.dartlang.org"
388 | source: hosted
389 | version: "2.1.8"
390 | matcher:
391 | dependency: transitive
392 | description:
393 | name: matcher
394 | url: "https://pub.dartlang.org"
395 | source: hosted
396 | version: "0.12.8"
397 | meta:
398 | dependency: transitive
399 | description:
400 | name: meta
401 | url: "https://pub.dartlang.org"
402 | source: hosted
403 | version: "1.1.8"
404 | mime:
405 | dependency: transitive
406 | description:
407 | name: mime
408 | url: "https://pub.dartlang.org"
409 | source: hosted
410 | version: "0.9.7"
411 | mobx:
412 | dependency: "direct main"
413 | description:
414 | name: mobx
415 | url: "https://pub.dartlang.org"
416 | source: hosted
417 | version: "1.2.1+3"
418 | mobx_codegen:
419 | dependency: "direct main"
420 | description:
421 | name: mobx_codegen
422 | url: "https://pub.dartlang.org"
423 | source: hosted
424 | version: "1.1.1+1"
425 | node_interop:
426 | dependency: transitive
427 | description:
428 | name: node_interop
429 | url: "https://pub.dartlang.org"
430 | source: hosted
431 | version: "1.1.1"
432 | node_io:
433 | dependency: transitive
434 | description:
435 | name: node_io
436 | url: "https://pub.dartlang.org"
437 | source: hosted
438 | version: "1.1.1"
439 | oauth2:
440 | dependency: transitive
441 | description:
442 | name: oauth2
443 | url: "https://pub.dartlang.org"
444 | source: hosted
445 | version: "1.6.1"
446 | package_config:
447 | dependency: transitive
448 | description:
449 | name: package_config
450 | url: "https://pub.dartlang.org"
451 | source: hosted
452 | version: "1.9.3"
453 | path:
454 | dependency: transitive
455 | description:
456 | name: path
457 | url: "https://pub.dartlang.org"
458 | source: hosted
459 | version: "1.7.0"
460 | path_provider:
461 | dependency: transitive
462 | description:
463 | name: path_provider
464 | url: "https://pub.dartlang.org"
465 | source: hosted
466 | version: "1.6.18"
467 | path_provider_linux:
468 | dependency: transitive
469 | description:
470 | name: path_provider_linux
471 | url: "https://pub.dartlang.org"
472 | source: hosted
473 | version: "0.0.1+2"
474 | path_provider_macos:
475 | dependency: transitive
476 | description:
477 | name: path_provider_macos
478 | url: "https://pub.dartlang.org"
479 | source: hosted
480 | version: "0.0.4+4"
481 | path_provider_platform_interface:
482 | dependency: transitive
483 | description:
484 | name: path_provider_platform_interface
485 | url: "https://pub.dartlang.org"
486 | source: hosted
487 | version: "1.0.3"
488 | path_provider_windows:
489 | dependency: transitive
490 | description:
491 | name: path_provider_windows
492 | url: "https://pub.dartlang.org"
493 | source: hosted
494 | version: "0.0.4+1"
495 | pedantic:
496 | dependency: transitive
497 | description:
498 | name: pedantic
499 | url: "https://pub.dartlang.org"
500 | source: hosted
501 | version: "1.9.0"
502 | petitparser:
503 | dependency: transitive
504 | description:
505 | name: petitparser
506 | url: "https://pub.dartlang.org"
507 | source: hosted
508 | version: "3.0.4"
509 | platform:
510 | dependency: transitive
511 | description:
512 | name: platform
513 | url: "https://pub.dartlang.org"
514 | source: hosted
515 | version: "2.2.1"
516 | plugin_platform_interface:
517 | dependency: transitive
518 | description:
519 | name: plugin_platform_interface
520 | url: "https://pub.dartlang.org"
521 | source: hosted
522 | version: "1.0.3"
523 | pool:
524 | dependency: transitive
525 | description:
526 | name: pool
527 | url: "https://pub.dartlang.org"
528 | source: hosted
529 | version: "1.4.0"
530 | process:
531 | dependency: transitive
532 | description:
533 | name: process
534 | url: "https://pub.dartlang.org"
535 | source: hosted
536 | version: "3.0.13"
537 | pub_semver:
538 | dependency: transitive
539 | description:
540 | name: pub_semver
541 | url: "https://pub.dartlang.org"
542 | source: hosted
543 | version: "1.4.4"
544 | pubspec_parse:
545 | dependency: transitive
546 | description:
547 | name: pubspec_parse
548 | url: "https://pub.dartlang.org"
549 | source: hosted
550 | version: "0.1.5"
551 | quiver:
552 | dependency: transitive
553 | description:
554 | name: quiver
555 | url: "https://pub.dartlang.org"
556 | source: hosted
557 | version: "2.1.3"
558 | shared_preferences:
559 | dependency: "direct main"
560 | description:
561 | name: shared_preferences
562 | url: "https://pub.dartlang.org"
563 | source: hosted
564 | version: "0.5.12"
565 | shared_preferences_linux:
566 | dependency: transitive
567 | description:
568 | name: shared_preferences_linux
569 | url: "https://pub.dartlang.org"
570 | source: hosted
571 | version: "0.0.2+2"
572 | shared_preferences_macos:
573 | dependency: transitive
574 | description:
575 | name: shared_preferences_macos
576 | url: "https://pub.dartlang.org"
577 | source: hosted
578 | version: "0.0.1+10"
579 | shared_preferences_platform_interface:
580 | dependency: transitive
581 | description:
582 | name: shared_preferences_platform_interface
583 | url: "https://pub.dartlang.org"
584 | source: hosted
585 | version: "1.0.4"
586 | shared_preferences_web:
587 | dependency: transitive
588 | description:
589 | name: shared_preferences_web
590 | url: "https://pub.dartlang.org"
591 | source: hosted
592 | version: "0.1.2+7"
593 | shared_preferences_windows:
594 | dependency: transitive
595 | description:
596 | name: shared_preferences_windows
597 | url: "https://pub.dartlang.org"
598 | source: hosted
599 | version: "0.0.1+1"
600 | shelf:
601 | dependency: transitive
602 | description:
603 | name: shelf
604 | url: "https://pub.dartlang.org"
605 | source: hosted
606 | version: "0.7.9"
607 | shelf_web_socket:
608 | dependency: transitive
609 | description:
610 | name: shelf_web_socket
611 | url: "https://pub.dartlang.org"
612 | source: hosted
613 | version: "0.2.3"
614 | sky_engine:
615 | dependency: transitive
616 | description: flutter
617 | source: sdk
618 | version: "0.0.99"
619 | source_gen:
620 | dependency: transitive
621 | description:
622 | name: source_gen
623 | url: "https://pub.dartlang.org"
624 | source: hosted
625 | version: "0.9.7+1"
626 | source_span:
627 | dependency: transitive
628 | description:
629 | name: source_span
630 | url: "https://pub.dartlang.org"
631 | source: hosted
632 | version: "1.7.0"
633 | stack_trace:
634 | dependency: transitive
635 | description:
636 | name: stack_trace
637 | url: "https://pub.dartlang.org"
638 | source: hosted
639 | version: "1.9.5"
640 | stream_channel:
641 | dependency: transitive
642 | description:
643 | name: stream_channel
644 | url: "https://pub.dartlang.org"
645 | source: hosted
646 | version: "2.0.0"
647 | stream_transform:
648 | dependency: transitive
649 | description:
650 | name: stream_transform
651 | url: "https://pub.dartlang.org"
652 | source: hosted
653 | version: "1.2.0"
654 | string_scanner:
655 | dependency: transitive
656 | description:
657 | name: string_scanner
658 | url: "https://pub.dartlang.org"
659 | source: hosted
660 | version: "1.0.5"
661 | term_glyph:
662 | dependency: transitive
663 | description:
664 | name: term_glyph
665 | url: "https://pub.dartlang.org"
666 | source: hosted
667 | version: "1.1.0"
668 | test_api:
669 | dependency: transitive
670 | description:
671 | name: test_api
672 | url: "https://pub.dartlang.org"
673 | source: hosted
674 | version: "0.2.17"
675 | timing:
676 | dependency: transitive
677 | description:
678 | name: timing
679 | url: "https://pub.dartlang.org"
680 | source: hosted
681 | version: "0.1.1+2"
682 | transparent_image:
683 | dependency: "direct main"
684 | description:
685 | name: transparent_image
686 | url: "https://pub.dartlang.org"
687 | source: hosted
688 | version: "1.0.0"
689 | typed_data:
690 | dependency: transitive
691 | description:
692 | name: typed_data
693 | url: "https://pub.dartlang.org"
694 | source: hosted
695 | version: "1.2.0"
696 | url_launcher:
697 | dependency: "direct main"
698 | description:
699 | name: url_launcher
700 | url: "https://pub.dartlang.org"
701 | source: hosted
702 | version: "5.7.2"
703 | url_launcher_linux:
704 | dependency: transitive
705 | description:
706 | name: url_launcher_linux
707 | url: "https://pub.dartlang.org"
708 | source: hosted
709 | version: "0.0.1+1"
710 | url_launcher_macos:
711 | dependency: transitive
712 | description:
713 | name: url_launcher_macos
714 | url: "https://pub.dartlang.org"
715 | source: hosted
716 | version: "0.0.1+8"
717 | url_launcher_platform_interface:
718 | dependency: transitive
719 | description:
720 | name: url_launcher_platform_interface
721 | url: "https://pub.dartlang.org"
722 | source: hosted
723 | version: "1.0.8"
724 | url_launcher_web:
725 | dependency: transitive
726 | description:
727 | name: url_launcher_web
728 | url: "https://pub.dartlang.org"
729 | source: hosted
730 | version: "0.1.4+1"
731 | url_launcher_windows:
732 | dependency: transitive
733 | description:
734 | name: url_launcher_windows
735 | url: "https://pub.dartlang.org"
736 | source: hosted
737 | version: "0.0.1+1"
738 | uuid:
739 | dependency: "direct main"
740 | description:
741 | name: uuid
742 | url: "https://pub.dartlang.org"
743 | source: hosted
744 | version: "2.2.2"
745 | vector_math:
746 | dependency: transitive
747 | description:
748 | name: vector_math
749 | url: "https://pub.dartlang.org"
750 | source: hosted
751 | version: "2.0.8"
752 | watcher:
753 | dependency: transitive
754 | description:
755 | name: watcher
756 | url: "https://pub.dartlang.org"
757 | source: hosted
758 | version: "0.9.7+15"
759 | web_socket_channel:
760 | dependency: transitive
761 | description:
762 | name: web_socket_channel
763 | url: "https://pub.dartlang.org"
764 | source: hosted
765 | version: "1.1.0"
766 | win32:
767 | dependency: transitive
768 | description:
769 | name: win32
770 | url: "https://pub.dartlang.org"
771 | source: hosted
772 | version: "1.7.3"
773 | xdg_directories:
774 | dependency: transitive
775 | description:
776 | name: xdg_directories
777 | url: "https://pub.dartlang.org"
778 | source: hosted
779 | version: "0.1.0"
780 | xml:
781 | dependency: transitive
782 | description:
783 | name: xml
784 | url: "https://pub.dartlang.org"
785 | source: hosted
786 | version: "4.5.1"
787 | yaml:
788 | dependency: transitive
789 | description:
790 | name: yaml
791 | url: "https://pub.dartlang.org"
792 | source: hosted
793 | version: "2.2.1"
794 | sdks:
795 | dart: ">=2.9.0-14.0.dev <3.0.0"
796 | flutter: ">=1.17.0 <2.0.0"
797 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutterreddit
2 | description: A flutter reddit app
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 2.0.0+5
19 |
20 | environment:
21 | sdk: ">=2.7.0 <3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 | draw: ^0.9.1
27 | mobx: ^1.2.1+1
28 | mobx_codegen: ^1.1.0+1
29 | build_runner: ^1.10.0
30 | flutter_mobx: ^1.1.0+1
31 | url_launcher: ^5.4.11
32 | flutter_web_browser: "^0.11.0"
33 | shared_preferences: ^0.5.10
34 | cupertino_icons: ^0.1.3
35 | flutter_webview_plugin: ^0.3.11
36 | uuid: 2.2.2
37 | google_fonts: ^1.1.0
38 | eva_icons_flutter: ^2.0.1
39 | transparent_image: ^1.0.0
40 | intl: ^0.15.6
41 | flutter_markdown: ^0.4.4
42 |
43 | dev_dependencies:
44 | flutter_test:
45 | sdk: flutter
46 | flutter_launcher_icons: ^0.7.5
47 |
48 | flutter_icons:
49 | ios: true
50 | android: true
51 | image_path: "assets/icon/rettericon.png"
52 |
53 | # For information on the generic Dart part of this file, see the
54 | # following page: https://dart.dev/tools/pub/pubspec
55 |
56 | # The following section is specific to Flutter.
57 | flutter:
58 | assets:
59 | - assets/
60 |
61 | # The following line ensures that the Material Icons font is
62 | # included with your application, so that you can use the icons in
63 | # the material Icons class.
64 | uses-material-design: true
--------------------------------------------------------------------------------
/screenshots/Video thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/Video thumbnail.jpg
--------------------------------------------------------------------------------
/screenshots/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/img1.png
--------------------------------------------------------------------------------
/screenshots/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/img2.png
--------------------------------------------------------------------------------
/screenshots/img3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/img3.jpg
--------------------------------------------------------------------------------
/screenshots/img4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/img4.jpg
--------------------------------------------------------------------------------
/screenshots/img5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matekdev/Retter/c5a8ebbcd7dc1e3e9c9736af89c610933699355a/screenshots/img5.jpg
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | //import 'package:flutter/material.dart';
9 | //import 'package:flutter_test/flutter_test.dart';
10 | //
11 | //
12 | //void main() {
13 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
14 | // // Build our app and trigger a frame.
15 | // await tester.pumpWidget(MyApp());
16 | //
17 | // // Verify that our counter starts at 0.
18 | // expect(find.text('0'), findsOneWidget);
19 | // expect(find.text('1'), findsNothing);
20 | //
21 | // // Tap the '+' icon and trigger a frame.
22 | // await tester.tap(find.byIcon(Icons.add));
23 | // await tester.pump();
24 | //
25 | // // Verify that our counter has incremented.
26 | // expect(find.text('0'), findsNothing);
27 | // expect(find.text('1'), findsOneWidget);
28 | // });
29 | //}
30 |
--------------------------------------------------------------------------------